diff options
Diffstat (limited to 'drivers')
96 files changed, 7906 insertions, 709 deletions
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 448ce5e29c56..dca5834685cf 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c | |||
@@ -486,8 +486,7 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) | |||
486 | } | 486 | } |
487 | 487 | ||
488 | sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev)); | 488 | sprintf(devp->hd_name, "hpet%d", (int)(devp - hpetp->hp_dev)); |
489 | irq_flags = devp->hd_flags & HPET_SHARED_IRQ | 489 | irq_flags = devp->hd_flags & HPET_SHARED_IRQ ? IRQF_SHARED : 0; |
490 | ? IRQF_SHARED : IRQF_DISABLED; | ||
491 | if (request_irq(irq, hpet_interrupt, irq_flags, | 490 | if (request_irq(irq, hpet_interrupt, irq_flags, |
492 | devp->hd_name, (void *)devp)) { | 491 | devp->hd_name, (void *)devp)) { |
493 | printk(KERN_ERR "hpet: IRQ %d is not free\n", irq); | 492 | printk(KERN_ERR "hpet: IRQ %d is not free\n", irq); |
@@ -971,8 +970,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) | |||
971 | struct acpi_resource_fixed_memory32 *fixmem32; | 970 | struct acpi_resource_fixed_memory32 *fixmem32; |
972 | 971 | ||
973 | fixmem32 = &res->data.fixed_memory32; | 972 | fixmem32 = &res->data.fixed_memory32; |
974 | if (!fixmem32) | ||
975 | return AE_NO_MEMORY; | ||
976 | 973 | ||
977 | hdp->hd_phys_address = fixmem32->address; | 974 | hdp->hd_phys_address = fixmem32->address; |
978 | hdp->hd_address = ioremap(fixmem32->address, | 975 | 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/nwbutton.c b/drivers/char/nwbutton.c index cfdfe493c6af..1fd00dc06897 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c | |||
@@ -220,7 +220,7 @@ static int __init nwbutton_init(void) | |||
220 | return -EBUSY; | 220 | return -EBUSY; |
221 | } | 221 | } |
222 | 222 | ||
223 | if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, IRQF_DISABLED, | 223 | if (request_irq (IRQ_NETWINDER_BUTTON, button_handler, 0, |
224 | "nwbutton", NULL)) { | 224 | "nwbutton", NULL)) { |
225 | printk (KERN_WARNING "nwbutton: IRQ %d is not free.\n", | 225 | printk (KERN_WARNING "nwbutton: IRQ %d is not free.\n", |
226 | IRQ_NETWINDER_BUTTON); | 226 | IRQ_NETWINDER_BUTTON); |
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index c0cbbd429bdc..35259961cc38 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c | |||
@@ -227,7 +227,7 @@ static inline unsigned char rtc_is_updating(void) | |||
227 | 227 | ||
228 | #ifdef RTC_IRQ | 228 | #ifdef RTC_IRQ |
229 | /* | 229 | /* |
230 | * A very tiny interrupt handler. It runs with IRQF_DISABLED set, | 230 | * A very tiny interrupt handler. It runs with interrupts disabled, |
231 | * but there is possibility of conflicting with the set_rtc_mmss() | 231 | * but there is possibility of conflicting with the set_rtc_mmss() |
232 | * call (the rtc irq and the timer irq can easily run at the same | 232 | * call (the rtc irq and the timer irq can easily run at the same |
233 | * time in two different CPUs). So we need to serialize | 233 | * time in two different CPUs). So we need to serialize |
@@ -1040,8 +1040,7 @@ no_irq: | |||
1040 | rtc_int_handler_ptr = rtc_interrupt; | 1040 | rtc_int_handler_ptr = rtc_interrupt; |
1041 | } | 1041 | } |
1042 | 1042 | ||
1043 | if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, | 1043 | if (request_irq(RTC_IRQ, rtc_int_handler_ptr, 0, "rtc", NULL)) { |
1044 | "rtc", NULL)) { | ||
1045 | /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ | 1044 | /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ |
1046 | rtc_has_irq = 0; | 1045 | rtc_has_irq = 0; |
1047 | printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); | 1046 | printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); |
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index 5816b39ff5a9..8bab59292a0d 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c | |||
@@ -108,8 +108,7 @@ scdrv_open(struct inode *inode, struct file *file) | |||
108 | /* hook this subchannel up to the system controller interrupt */ | 108 | /* hook this subchannel up to the system controller interrupt */ |
109 | mutex_lock(&scdrv_mutex); | 109 | mutex_lock(&scdrv_mutex); |
110 | rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt, | 110 | rv = request_irq(SGI_UART_VECTOR, scdrv_interrupt, |
111 | IRQF_SHARED | IRQF_DISABLED, | 111 | IRQF_SHARED, SYSCTL_BASENAME, sd); |
112 | SYSCTL_BASENAME, sd); | ||
113 | if (rv) { | 112 | if (rv) { |
114 | ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch); | 113 | ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch); |
115 | kfree(sd); | 114 | kfree(sd); |
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c index ee156948b9f8..59bcefd6ec7c 100644 --- a/drivers/char/snsc_event.c +++ b/drivers/char/snsc_event.c | |||
@@ -292,8 +292,7 @@ scdrv_event_init(struct sysctl_data_s *scd) | |||
292 | 292 | ||
293 | /* hook event subchannel up to the system controller interrupt */ | 293 | /* hook event subchannel up to the system controller interrupt */ |
294 | rv = request_irq(SGI_UART_VECTOR, scdrv_event_interrupt, | 294 | rv = request_irq(SGI_UART_VECTOR, scdrv_event_interrupt, |
295 | IRQF_SHARED | IRQF_DISABLED, | 295 | IRQF_SHARED, "system controller events", event_sd); |
296 | "system controller events", event_sd); | ||
297 | if (rv) { | 296 | if (rv) { |
298 | printk(KERN_WARNING "%s: irq request failed (%d)\n", | 297 | printk(KERN_WARNING "%s: irq request failed (%d)\n", |
299 | __func__, rv); | 298 | __func__, rv); |
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index e95e0ab0bd87..100cd1de9939 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c | |||
@@ -222,7 +222,7 @@ static int tlclk_open(struct inode *inode, struct file *filp) | |||
222 | /* This device is wired through the FPGA IO space of the ATCA blade | 222 | /* This device is wired through the FPGA IO space of the ATCA blade |
223 | * we can't share this IRQ */ | 223 | * we can't share this IRQ */ |
224 | result = request_irq(telclk_interrupt, &tlclk_interrupt, | 224 | result = request_irq(telclk_interrupt, &tlclk_interrupt, |
225 | IRQF_DISABLED, "telco_clock", tlclk_interrupt); | 225 | 0, "telco_clock", tlclk_interrupt); |
226 | if (result == -EBUSY) | 226 | if (result == -EBUSY) |
227 | printk(KERN_ERR "tlclk: Interrupt can't be reserved.\n"); | 227 | printk(KERN_ERR "tlclk: Interrupt can't be reserved.\n"); |
228 | else | 228 | else |
diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 5224da5202d3..f6345f932e46 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; |
@@ -731,7 +731,6 @@ static int hwicap_remove(struct device *dev) | |||
731 | iounmap(drvdata->base_address); | 731 | iounmap(drvdata->base_address); |
732 | release_mem_region(drvdata->mem_start, drvdata->mem_size); | 732 | release_mem_region(drvdata->mem_start, drvdata->mem_size); |
733 | kfree(drvdata); | 733 | kfree(drvdata); |
734 | dev_set_drvdata(dev, NULL); | ||
735 | 734 | ||
736 | mutex_lock(&icap_sem); | 735 | mutex_lock(&icap_sem); |
737 | probed_devices[MINOR(dev->devt)-XHWICAP_MINOR] = 0; | 736 | probed_devices[MINOR(dev->devt)-XHWICAP_MINOR] = 0; |
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c index 5985807e52c9..e23f1c2e5053 100644 --- a/drivers/extcon/extcon-adc-jack.c +++ b/drivers/extcon/extcon-adc-jack.c | |||
@@ -27,16 +27,16 @@ | |||
27 | 27 | ||
28 | /** | 28 | /** |
29 | * struct adc_jack_data - internal data for adc_jack device driver | 29 | * struct adc_jack_data - internal data for adc_jack device driver |
30 | * @edev - extcon device. | 30 | * @edev: extcon device. |
31 | * @cable_names - list of supported cables. | 31 | * @cable_names: list of supported cables. |
32 | * @num_cables - size of cable_names. | 32 | * @num_cables: size of cable_names. |
33 | * @adc_conditions - list of adc value conditions. | 33 | * @adc_conditions: list of adc value conditions. |
34 | * @num_conditions - size of adc_conditions. | 34 | * @num_conditions: size of adc_conditions. |
35 | * @irq - irq number of attach/detach event (0 if not exist). | 35 | * @irq: irq number of attach/detach event (0 if not exist). |
36 | * @handling_delay - interrupt handler will schedule extcon event | 36 | * @handling_delay: interrupt handler will schedule extcon event |
37 | * handling at handling_delay jiffies. | 37 | * handling at handling_delay jiffies. |
38 | * @handler - extcon event handler called by interrupt handler. | 38 | * @handler: extcon event handler called by interrupt handler. |
39 | * @chan - iio channel being queried. | 39 | * @chan: iio channel being queried. |
40 | */ | 40 | */ |
41 | struct adc_jack_data { | 41 | struct adc_jack_data { |
42 | struct extcon_dev edev; | 42 | struct extcon_dev edev; |
@@ -64,7 +64,7 @@ static void adc_jack_handler(struct work_struct *work) | |||
64 | 64 | ||
65 | ret = iio_read_channel_raw(data->chan, &adc_val); | 65 | ret = iio_read_channel_raw(data->chan, &adc_val); |
66 | if (ret < 0) { | 66 | if (ret < 0) { |
67 | dev_err(data->edev.dev, "read channel() error: %d\n", ret); | 67 | dev_err(&data->edev.dev, "read channel() error: %d\n", ret); |
68 | return; | 68 | return; |
69 | } | 69 | } |
70 | 70 | ||
@@ -95,7 +95,7 @@ static irqreturn_t adc_jack_irq_thread(int irq, void *_data) | |||
95 | static int adc_jack_probe(struct platform_device *pdev) | 95 | static int adc_jack_probe(struct platform_device *pdev) |
96 | { | 96 | { |
97 | struct adc_jack_data *data; | 97 | struct adc_jack_data *data; |
98 | struct adc_jack_pdata *pdata = pdev->dev.platform_data; | 98 | struct adc_jack_pdata *pdata = dev_get_platdata(&pdev->dev); |
99 | int i, err = 0; | 99 | int i, err = 0; |
100 | 100 | ||
101 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | 101 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); |
@@ -110,6 +110,7 @@ static int adc_jack_probe(struct platform_device *pdev) | |||
110 | goto out; | 110 | goto out; |
111 | } | 111 | } |
112 | 112 | ||
113 | data->edev.dev.parent = &pdev->dev; | ||
113 | data->edev.supported_cable = pdata->cable_names; | 114 | data->edev.supported_cable = pdata->cable_names; |
114 | 115 | ||
115 | /* Check the length of array and set num_cables */ | 116 | /* Check the length of array and set num_cables */ |
@@ -148,7 +149,7 @@ static int adc_jack_probe(struct platform_device *pdev) | |||
148 | 149 | ||
149 | platform_set_drvdata(pdev, data); | 150 | platform_set_drvdata(pdev, data); |
150 | 151 | ||
151 | err = extcon_dev_register(&data->edev, &pdev->dev); | 152 | err = extcon_dev_register(&data->edev); |
152 | if (err) | 153 | if (err) |
153 | goto out; | 154 | goto out; |
154 | 155 | ||
diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index e55713083c78..3c55ec856e39 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c | |||
@@ -86,8 +86,8 @@ struct arizona_extcon_info { | |||
86 | }; | 86 | }; |
87 | 87 | ||
88 | static const struct arizona_micd_config micd_default_modes[] = { | 88 | static const struct arizona_micd_config micd_default_modes[] = { |
89 | { ARIZONA_ACCDET_SRC, 1 << ARIZONA_MICD_BIAS_SRC_SHIFT, 0 }, | 89 | { ARIZONA_ACCDET_SRC, 1, 0 }, |
90 | { 0, 2 << ARIZONA_MICD_BIAS_SRC_SHIFT, 1 }, | 90 | { 0, 2, 1 }, |
91 | }; | 91 | }; |
92 | 92 | ||
93 | static const struct arizona_micd_range micd_default_ranges[] = { | 93 | static const struct arizona_micd_range micd_default_ranges[] = { |
@@ -182,7 +182,8 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) | |||
182 | info->micd_modes[mode].gpio); | 182 | info->micd_modes[mode].gpio); |
183 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, | 183 | regmap_update_bits(arizona->regmap, ARIZONA_MIC_DETECT_1, |
184 | ARIZONA_MICD_BIAS_SRC_MASK, | 184 | ARIZONA_MICD_BIAS_SRC_MASK, |
185 | info->micd_modes[mode].bias); | 185 | info->micd_modes[mode].bias << |
186 | ARIZONA_MICD_BIAS_SRC_SHIFT); | ||
186 | regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, | 187 | regmap_update_bits(arizona->regmap, ARIZONA_ACCESSORY_DETECT_MODE_1, |
187 | ARIZONA_ACCDET_SRC, info->micd_modes[mode].src); | 188 | ARIZONA_ACCDET_SRC, info->micd_modes[mode].src); |
188 | 189 | ||
@@ -193,7 +194,7 @@ static void arizona_extcon_set_mode(struct arizona_extcon_info *info, int mode) | |||
193 | 194 | ||
194 | static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info) | 195 | static const char *arizona_extcon_get_micbias(struct arizona_extcon_info *info) |
195 | { | 196 | { |
196 | switch (info->micd_modes[0].bias >> ARIZONA_MICD_BIAS_SRC_SHIFT) { | 197 | switch (info->micd_modes[0].bias) { |
197 | case 1: | 198 | case 1: |
198 | return "MICBIAS1"; | 199 | return "MICBIAS1"; |
199 | case 2: | 200 | case 2: |
@@ -388,7 +389,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) | |||
388 | >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT; | 389 | >> ARIZONA_HP_IMPEDANCE_RANGE_SHIFT; |
389 | 390 | ||
390 | if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 && | 391 | if (range < ARRAY_SIZE(arizona_hpdet_b_ranges) - 1 && |
391 | (val < 100 || val > 0x3fb)) { | 392 | (val < 100 || val >= 0x3fb)) { |
392 | range++; | 393 | range++; |
393 | dev_dbg(arizona->dev, "Moving to HPDET range %d\n", | 394 | dev_dbg(arizona->dev, "Moving to HPDET range %d\n", |
394 | range); | 395 | range); |
@@ -401,7 +402,7 @@ static int arizona_hpdet_read(struct arizona_extcon_info *info) | |||
401 | } | 402 | } |
402 | 403 | ||
403 | /* If we go out of range report top of range */ | 404 | /* If we go out of range report top of range */ |
404 | if (val < 100 || val > 0x3fb) { | 405 | if (val < 100 || val >= 0x3fb) { |
405 | dev_dbg(arizona->dev, "Measurement out of range\n"); | 406 | dev_dbg(arizona->dev, "Measurement out of range\n"); |
406 | return ARIZONA_HPDET_MAX; | 407 | return ARIZONA_HPDET_MAX; |
407 | } | 408 | } |
@@ -514,7 +515,7 @@ static int arizona_hpdet_do_id(struct arizona_extcon_info *info, int *reading, | |||
514 | } | 515 | } |
515 | 516 | ||
516 | /* | 517 | /* |
517 | * If we measure the mic as | 518 | * If we measure the mic as high impedance |
518 | */ | 519 | */ |
519 | if (!id_gpio || info->hpdet_res[1] > 50) { | 520 | if (!id_gpio || info->hpdet_res[1] > 50) { |
520 | dev_dbg(arizona->dev, "Detected mic\n"); | 521 | dev_dbg(arizona->dev, "Detected mic\n"); |
@@ -564,11 +565,10 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) | |||
564 | } | 565 | } |
565 | 566 | ||
566 | ret = arizona_hpdet_read(info); | 567 | ret = arizona_hpdet_read(info); |
567 | if (ret == -EAGAIN) { | 568 | if (ret == -EAGAIN) |
568 | goto out; | 569 | goto out; |
569 | } else if (ret < 0) { | 570 | else if (ret < 0) |
570 | goto done; | 571 | goto done; |
571 | } | ||
572 | reading = ret; | 572 | reading = ret; |
573 | 573 | ||
574 | /* Reset back to starting range */ | 574 | /* Reset back to starting range */ |
@@ -578,11 +578,10 @@ static irqreturn_t arizona_hpdet_irq(int irq, void *data) | |||
578 | 0); | 578 | 0); |
579 | 579 | ||
580 | ret = arizona_hpdet_do_id(info, &reading, &mic); | 580 | ret = arizona_hpdet_do_id(info, &reading, &mic); |
581 | if (ret == -EAGAIN) { | 581 | if (ret == -EAGAIN) |
582 | goto out; | 582 | goto out; |
583 | } else if (ret < 0) { | 583 | else if (ret < 0) |
584 | goto done; | 584 | goto done; |
585 | } | ||
586 | 585 | ||
587 | /* Report high impedence cables as line outputs */ | 586 | /* Report high impedence cables as line outputs */ |
588 | if (reading >= 5000) | 587 | if (reading >= 5000) |
@@ -738,8 +737,8 @@ err: | |||
738 | static void arizona_micd_timeout_work(struct work_struct *work) | 737 | static void arizona_micd_timeout_work(struct work_struct *work) |
739 | { | 738 | { |
740 | struct arizona_extcon_info *info = container_of(work, | 739 | struct arizona_extcon_info *info = container_of(work, |
741 | struct arizona_extcon_info, | 740 | struct arizona_extcon_info, |
742 | micd_timeout_work.work); | 741 | micd_timeout_work.work); |
743 | 742 | ||
744 | mutex_lock(&info->lock); | 743 | mutex_lock(&info->lock); |
745 | 744 | ||
@@ -756,8 +755,8 @@ static void arizona_micd_timeout_work(struct work_struct *work) | |||
756 | static void arizona_micd_detect(struct work_struct *work) | 755 | static void arizona_micd_detect(struct work_struct *work) |
757 | { | 756 | { |
758 | struct arizona_extcon_info *info = container_of(work, | 757 | struct arizona_extcon_info *info = container_of(work, |
759 | struct arizona_extcon_info, | 758 | struct arizona_extcon_info, |
760 | micd_detect_work.work); | 759 | micd_detect_work.work); |
761 | struct arizona *arizona = info->arizona; | 760 | struct arizona *arizona = info->arizona; |
762 | unsigned int val = 0, lvl; | 761 | unsigned int val = 0, lvl; |
763 | int ret, i, key; | 762 | int ret, i, key; |
@@ -769,7 +768,8 @@ static void arizona_micd_detect(struct work_struct *work) | |||
769 | for (i = 0; i < 10 && !(val & 0x7fc); i++) { | 768 | for (i = 0; i < 10 && !(val & 0x7fc); i++) { |
770 | ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); | 769 | ret = regmap_read(arizona->regmap, ARIZONA_MIC_DETECT_3, &val); |
771 | if (ret != 0) { | 770 | if (ret != 0) { |
772 | dev_err(arizona->dev, "Failed to read MICDET: %d\n", ret); | 771 | dev_err(arizona->dev, |
772 | "Failed to read MICDET: %d\n", ret); | ||
773 | mutex_unlock(&info->lock); | 773 | mutex_unlock(&info->lock); |
774 | return; | 774 | return; |
775 | } | 775 | } |
@@ -777,7 +777,8 @@ static void arizona_micd_detect(struct work_struct *work) | |||
777 | dev_dbg(arizona->dev, "MICDET: %x\n", val); | 777 | dev_dbg(arizona->dev, "MICDET: %x\n", val); |
778 | 778 | ||
779 | if (!(val & ARIZONA_MICD_VALID)) { | 779 | if (!(val & ARIZONA_MICD_VALID)) { |
780 | dev_warn(arizona->dev, "Microphone detection state invalid\n"); | 780 | dev_warn(arizona->dev, |
781 | "Microphone detection state invalid\n"); | ||
781 | mutex_unlock(&info->lock); | 782 | mutex_unlock(&info->lock); |
782 | return; | 783 | return; |
783 | } | 784 | } |
@@ -925,8 +926,8 @@ static irqreturn_t arizona_micdet(int irq, void *data) | |||
925 | static void arizona_hpdet_work(struct work_struct *work) | 926 | static void arizona_hpdet_work(struct work_struct *work) |
926 | { | 927 | { |
927 | struct arizona_extcon_info *info = container_of(work, | 928 | struct arizona_extcon_info *info = container_of(work, |
928 | struct arizona_extcon_info, | 929 | struct arizona_extcon_info, |
929 | hpdet_work.work); | 930 | hpdet_work.work); |
930 | 931 | ||
931 | mutex_lock(&info->lock); | 932 | mutex_lock(&info->lock); |
932 | arizona_start_hpdet_acc_id(info); | 933 | arizona_start_hpdet_acc_id(info); |
@@ -973,10 +974,13 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
973 | &info->hpdet_work, | 974 | &info->hpdet_work, |
974 | msecs_to_jiffies(HPDET_DEBOUNCE)); | 975 | msecs_to_jiffies(HPDET_DEBOUNCE)); |
975 | 976 | ||
976 | if (cancelled_mic) | 977 | if (cancelled_mic) { |
978 | int micd_timeout = info->micd_timeout; | ||
979 | |||
977 | queue_delayed_work(system_power_efficient_wq, | 980 | queue_delayed_work(system_power_efficient_wq, |
978 | &info->micd_timeout_work, | 981 | &info->micd_timeout_work, |
979 | msecs_to_jiffies(info->micd_timeout)); | 982 | msecs_to_jiffies(micd_timeout)); |
983 | } | ||
980 | 984 | ||
981 | goto out; | 985 | goto out; |
982 | } | 986 | } |
@@ -1039,6 +1043,7 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
1039 | else | 1043 | else |
1040 | info->micd_timeout = DEFAULT_MICD_TIMEOUT; | 1044 | info->micd_timeout = DEFAULT_MICD_TIMEOUT; |
1041 | 1045 | ||
1046 | out: | ||
1042 | /* Clear trig_sts to make sure DCVDD is not forced up */ | 1047 | /* Clear trig_sts to make sure DCVDD is not forced up */ |
1043 | regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG, | 1048 | regmap_write(arizona->regmap, ARIZONA_AOD_WKUP_AND_TRIG, |
1044 | ARIZONA_MICD_CLAMP_FALL_TRIG_STS | | 1049 | ARIZONA_MICD_CLAMP_FALL_TRIG_STS | |
@@ -1046,7 +1051,6 @@ static irqreturn_t arizona_jackdet(int irq, void *data) | |||
1046 | ARIZONA_JD1_FALL_TRIG_STS | | 1051 | ARIZONA_JD1_FALL_TRIG_STS | |
1047 | ARIZONA_JD1_RISE_TRIG_STS); | 1052 | ARIZONA_JD1_RISE_TRIG_STS); |
1048 | 1053 | ||
1049 | out: | ||
1050 | mutex_unlock(&info->lock); | 1054 | mutex_unlock(&info->lock); |
1051 | 1055 | ||
1052 | pm_runtime_mark_last_busy(info->dev); | 1056 | pm_runtime_mark_last_busy(info->dev); |
@@ -1129,9 +1133,10 @@ static int arizona_extcon_probe(struct platform_device *pdev) | |||
1129 | } | 1133 | } |
1130 | 1134 | ||
1131 | info->edev.name = "Headset Jack"; | 1135 | info->edev.name = "Headset Jack"; |
1136 | info->edev.dev.parent = arizona->dev; | ||
1132 | info->edev.supported_cable = arizona_cable; | 1137 | info->edev.supported_cable = arizona_cable; |
1133 | 1138 | ||
1134 | ret = extcon_dev_register(&info->edev, arizona->dev); | 1139 | ret = extcon_dev_register(&info->edev); |
1135 | if (ret < 0) { | 1140 | if (ret < 0) { |
1136 | dev_err(arizona->dev, "extcon_dev_register() failed: %d\n", | 1141 | dev_err(arizona->dev, "extcon_dev_register() failed: %d\n", |
1137 | ret); | 1142 | ret); |
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c index 148382faded9..15443d3b6be1 100644 --- a/drivers/extcon/extcon-class.c +++ b/drivers/extcon/extcon-class.c | |||
@@ -74,7 +74,7 @@ static DEFINE_MUTEX(extcon_dev_list_lock); | |||
74 | 74 | ||
75 | /** | 75 | /** |
76 | * check_mutually_exclusive - Check if new_state violates mutually_exclusive | 76 | * check_mutually_exclusive - Check if new_state violates mutually_exclusive |
77 | * condition. | 77 | * condition. |
78 | * @edev: the extcon device | 78 | * @edev: the extcon device |
79 | * @new_state: new cable attach status for @edev | 79 | * @new_state: new cable attach status for @edev |
80 | * | 80 | * |
@@ -105,7 +105,7 @@ static ssize_t state_show(struct device *dev, struct device_attribute *attr, | |||
105 | char *buf) | 105 | char *buf) |
106 | { | 106 | { |
107 | int i, count = 0; | 107 | int i, count = 0; |
108 | struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev); | 108 | struct extcon_dev *edev = dev_get_drvdata(dev); |
109 | 109 | ||
110 | if (edev->print_state) { | 110 | if (edev->print_state) { |
111 | int ret = edev->print_state(edev, buf); | 111 | int ret = edev->print_state(edev, buf); |
@@ -129,13 +129,12 @@ 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 | { |
136 | u32 state; | 135 | u32 state; |
137 | ssize_t ret = 0; | 136 | ssize_t ret = 0; |
138 | struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev); | 137 | struct extcon_dev *edev = dev_get_drvdata(dev); |
139 | 138 | ||
140 | ret = sscanf(buf, "0x%x", &state); | 139 | ret = sscanf(buf, "0x%x", &state); |
141 | if (ret == 0) | 140 | if (ret == 0) |
@@ -153,7 +152,7 @@ static DEVICE_ATTR_RW(state); | |||
153 | static ssize_t name_show(struct device *dev, struct device_attribute *attr, | 152 | static ssize_t name_show(struct device *dev, struct device_attribute *attr, |
154 | char *buf) | 153 | char *buf) |
155 | { | 154 | { |
156 | struct extcon_dev *edev = (struct extcon_dev *) dev_get_drvdata(dev); | 155 | struct extcon_dev *edev = dev_get_drvdata(dev); |
157 | 156 | ||
158 | /* Optional callback given by the user */ | 157 | /* Optional callback given by the user */ |
159 | if (edev->print_name) { | 158 | if (edev->print_name) { |
@@ -162,7 +161,7 @@ static ssize_t name_show(struct device *dev, struct device_attribute *attr, | |||
162 | return ret; | 161 | return ret; |
163 | } | 162 | } |
164 | 163 | ||
165 | return sprintf(buf, "%s\n", dev_name(edev->dev)); | 164 | return sprintf(buf, "%s\n", dev_name(&edev->dev)); |
166 | } | 165 | } |
167 | static DEVICE_ATTR_RO(name); | 166 | static DEVICE_ATTR_RO(name); |
168 | 167 | ||
@@ -189,7 +188,7 @@ static ssize_t cable_state_show(struct device *dev, | |||
189 | 188 | ||
190 | /** | 189 | /** |
191 | * extcon_update_state() - Update the cable attach states of the extcon device | 190 | * extcon_update_state() - Update the cable attach states of the extcon device |
192 | * only for the masked bits. | 191 | * only for the masked bits. |
193 | * @edev: the extcon device | 192 | * @edev: the extcon device |
194 | * @mask: the bit mask to designate updated bits. | 193 | * @mask: the bit mask to designate updated bits. |
195 | * @state: new cable attach status for @edev | 194 | * @state: new cable attach status for @edev |
@@ -227,11 +226,10 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) | |||
227 | edev->state |= state & mask; | 226 | edev->state |= state & mask; |
228 | 227 | ||
229 | raw_notifier_call_chain(&edev->nh, old_state, edev); | 228 | raw_notifier_call_chain(&edev->nh, old_state, edev); |
230 | |||
231 | /* This could be in interrupt handler */ | 229 | /* This could be in interrupt handler */ |
232 | prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); | 230 | prop_buf = (char *)get_zeroed_page(GFP_ATOMIC); |
233 | if (prop_buf) { | 231 | if (prop_buf) { |
234 | length = name_show(edev->dev, NULL, prop_buf); | 232 | length = name_show(&edev->dev, NULL, prop_buf); |
235 | if (length > 0) { | 233 | if (length > 0) { |
236 | if (prop_buf[length - 1] == '\n') | 234 | if (prop_buf[length - 1] == '\n') |
237 | prop_buf[length - 1] = 0; | 235 | prop_buf[length - 1] = 0; |
@@ -239,7 +237,7 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) | |||
239 | "NAME=%s", prop_buf); | 237 | "NAME=%s", prop_buf); |
240 | envp[env_offset++] = name_buf; | 238 | envp[env_offset++] = name_buf; |
241 | } | 239 | } |
242 | length = state_show(edev->dev, NULL, prop_buf); | 240 | length = state_show(&edev->dev, NULL, prop_buf); |
243 | if (length > 0) { | 241 | if (length > 0) { |
244 | if (prop_buf[length - 1] == '\n') | 242 | if (prop_buf[length - 1] == '\n') |
245 | prop_buf[length - 1] = 0; | 243 | prop_buf[length - 1] = 0; |
@@ -251,14 +249,14 @@ int extcon_update_state(struct extcon_dev *edev, u32 mask, u32 state) | |||
251 | /* Unlock early before uevent */ | 249 | /* Unlock early before uevent */ |
252 | spin_unlock_irqrestore(&edev->lock, flags); | 250 | spin_unlock_irqrestore(&edev->lock, flags); |
253 | 251 | ||
254 | kobject_uevent_env(&edev->dev->kobj, KOBJ_CHANGE, envp); | 252 | kobject_uevent_env(&edev->dev.kobj, KOBJ_CHANGE, envp); |
255 | free_page((unsigned long)prop_buf); | 253 | free_page((unsigned long)prop_buf); |
256 | } else { | 254 | } else { |
257 | /* Unlock early before uevent */ | 255 | /* Unlock early before uevent */ |
258 | spin_unlock_irqrestore(&edev->lock, flags); | 256 | spin_unlock_irqrestore(&edev->lock, flags); |
259 | 257 | ||
260 | dev_err(edev->dev, "out of memory in extcon_set_state\n"); | 258 | dev_err(&edev->dev, "out of memory in extcon_set_state\n"); |
261 | kobject_uevent(&edev->dev->kobj, KOBJ_CHANGE); | 259 | kobject_uevent(&edev->dev.kobj, KOBJ_CHANGE); |
262 | } | 260 | } |
263 | } else { | 261 | } else { |
264 | /* No changes */ | 262 | /* No changes */ |
@@ -339,8 +337,9 @@ EXPORT_SYMBOL_GPL(extcon_get_cable_state); | |||
339 | 337 | ||
340 | /** | 338 | /** |
341 | * extcon_set_cable_state_() - Set the status of a specific cable. | 339 | * extcon_set_cable_state_() - Set the status of a specific cable. |
342 | * @edev: the extcon device that has the cable. | 340 | * @edev: the extcon device that has the cable. |
343 | * @index: cable index that can be retrieved by extcon_find_cable_index(). | 341 | * @index: cable index that can be retrieved by |
342 | * extcon_find_cable_index(). | ||
344 | * @cable_state: the new cable status. The default semantics is | 343 | * @cable_state: the new cable status. The default semantics is |
345 | * true: attached / false: detached. | 344 | * true: attached / false: detached. |
346 | */ | 345 | */ |
@@ -359,8 +358,8 @@ EXPORT_SYMBOL_GPL(extcon_set_cable_state_); | |||
359 | 358 | ||
360 | /** | 359 | /** |
361 | * extcon_set_cable_state() - Set the status of a specific cable. | 360 | * extcon_set_cable_state() - Set the status of a specific cable. |
362 | * @edev: the extcon device that has the cable. | 361 | * @edev: the extcon device that has the cable. |
363 | * @cable_name: cable name. | 362 | * @cable_name: cable name. |
364 | * @cable_state: the new cable status. The default semantics is | 363 | * @cable_state: the new cable status. The default semantics is |
365 | * true: attached / false: detached. | 364 | * true: attached / false: detached. |
366 | * | 365 | * |
@@ -419,14 +418,14 @@ static int _call_per_cable(struct notifier_block *nb, unsigned long val, | |||
419 | 418 | ||
420 | /** | 419 | /** |
421 | * extcon_register_interest() - Register a notifier for a state change of a | 420 | * extcon_register_interest() - Register a notifier for a state change of a |
422 | * specific cable, not an entier set of cables of a | 421 | * specific cable, not an entier set of cables of a |
423 | * extcon device. | 422 | * extcon device. |
424 | * @obj: an empty extcon_specific_cable_nb object to be returned. | 423 | * @obj: an empty extcon_specific_cable_nb object to be returned. |
425 | * @extcon_name: the name of extcon device. | 424 | * @extcon_name: the name of extcon device. |
426 | * if NULL, extcon_register_interest will register | 425 | * if NULL, extcon_register_interest will register |
427 | * every cable with the target cable_name given. | 426 | * every cable with the target cable_name given. |
428 | * @cable_name: the target cable name. | 427 | * @cable_name: the target cable name. |
429 | * @nb: the notifier block to get notified. | 428 | * @nb: the notifier block to get notified. |
430 | * | 429 | * |
431 | * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets | 430 | * Provide an empty extcon_specific_cable_nb. extcon_register_interest() sets |
432 | * the struct for you. | 431 | * the struct for you. |
@@ -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; |
@@ -470,7 +471,7 @@ int extcon_register_interest(struct extcon_specific_cable_nb *obj, | |||
470 | return -ENODEV; | 471 | return -ENODEV; |
471 | class_dev_iter_init(&iter, extcon_class, NULL, NULL); | 472 | class_dev_iter_init(&iter, extcon_class, NULL, NULL); |
472 | while ((dev = class_dev_iter_next(&iter))) { | 473 | while ((dev = class_dev_iter_next(&iter))) { |
473 | extd = (struct extcon_dev *)dev_get_drvdata(dev); | 474 | extd = dev_get_drvdata(dev); |
474 | 475 | ||
475 | if (extcon_find_cable_index(extd, cable_name) < 0) | 476 | if (extcon_find_cable_index(extd, cable_name) < 0) |
476 | continue; | 477 | continue; |
@@ -487,7 +488,7 @@ EXPORT_SYMBOL_GPL(extcon_register_interest); | |||
487 | 488 | ||
488 | /** | 489 | /** |
489 | * extcon_unregister_interest() - Unregister the notifier registered by | 490 | * extcon_unregister_interest() - Unregister the notifier registered by |
490 | * extcon_register_interest(). | 491 | * extcon_register_interest(). |
491 | * @obj: the extcon_specific_cable_nb object returned by | 492 | * @obj: the extcon_specific_cable_nb object returned by |
492 | * extcon_register_interest(). | 493 | * extcon_register_interest(). |
493 | */ | 494 | */ |
@@ -502,7 +503,7 @@ EXPORT_SYMBOL_GPL(extcon_unregister_interest); | |||
502 | 503 | ||
503 | /** | 504 | /** |
504 | * extcon_register_notifier() - Register a notifiee to get notified by | 505 | * extcon_register_notifier() - Register a notifiee to get notified by |
505 | * any attach status changes from the extcon. | 506 | * any attach status changes from the extcon. |
506 | * @edev: the extcon device. | 507 | * @edev: the extcon device. |
507 | * @nb: a notifier block to be registered. | 508 | * @nb: a notifier block to be registered. |
508 | * | 509 | * |
@@ -556,7 +557,6 @@ static int create_extcon_class(void) | |||
556 | 557 | ||
557 | static void extcon_dev_release(struct device *dev) | 558 | static void extcon_dev_release(struct device *dev) |
558 | { | 559 | { |
559 | kfree(dev); | ||
560 | } | 560 | } |
561 | 561 | ||
562 | static const char *muex_name = "mutually_exclusive"; | 562 | static const char *muex_name = "mutually_exclusive"; |
@@ -567,14 +567,13 @@ static void dummy_sysfs_dev_release(struct device *dev) | |||
567 | /** | 567 | /** |
568 | * extcon_dev_register() - Register a new extcon device | 568 | * extcon_dev_register() - Register a new extcon device |
569 | * @edev : the new extcon device (should be allocated before calling) | 569 | * @edev : the new extcon device (should be allocated before calling) |
570 | * @dev : the parent device for this extcon device. | ||
571 | * | 570 | * |
572 | * Among the members of edev struct, please set the "user initializing data" | 571 | * Among the members of edev struct, please set the "user initializing data" |
573 | * in any case and set the "optional callbacks" if required. However, please | 572 | * in any case and set the "optional callbacks" if required. However, please |
574 | * do not set the values of "internal data", which are initialized by | 573 | * do not set the values of "internal data", which are initialized by |
575 | * this function. | 574 | * this function. |
576 | */ | 575 | */ |
577 | int extcon_dev_register(struct extcon_dev *edev, struct device *dev) | 576 | int extcon_dev_register(struct extcon_dev *edev) |
578 | { | 577 | { |
579 | int ret, index = 0; | 578 | int ret, index = 0; |
580 | 579 | ||
@@ -594,19 +593,20 @@ int extcon_dev_register(struct extcon_dev *edev, struct device *dev) | |||
594 | } | 593 | } |
595 | 594 | ||
596 | if (index > SUPPORTED_CABLE_MAX) { | 595 | if (index > SUPPORTED_CABLE_MAX) { |
597 | dev_err(edev->dev, "extcon: maximum number of supported cables exceeded.\n"); | 596 | dev_err(&edev->dev, "extcon: maximum number of supported cables exceeded.\n"); |
598 | return -EINVAL; | 597 | return -EINVAL; |
599 | } | 598 | } |
600 | 599 | ||
601 | edev->dev = kzalloc(sizeof(struct device), GFP_KERNEL); | 600 | edev->dev.class = extcon_class; |
602 | if (!edev->dev) | 601 | edev->dev.release = extcon_dev_release; |
603 | return -ENOMEM; | ||
604 | edev->dev->parent = dev; | ||
605 | edev->dev->class = extcon_class; | ||
606 | edev->dev->release = extcon_dev_release; | ||
607 | 602 | ||
608 | edev->name = edev->name ? edev->name : dev_name(dev); | 603 | edev->name = edev->name ? edev->name : dev_name(edev->dev.parent); |
609 | dev_set_name(edev->dev, "%s", edev->name); | 604 | if (IS_ERR_OR_NULL(edev->name)) { |
605 | dev_err(&edev->dev, | ||
606 | "extcon device name is null\n"); | ||
607 | return -EINVAL; | ||
608 | } | ||
609 | dev_set_name(&edev->dev, "%s", edev->name); | ||
610 | 610 | ||
611 | if (edev->max_supported) { | 611 | if (edev->max_supported) { |
612 | char buf[10]; | 612 | char buf[10]; |
@@ -714,7 +714,7 @@ int extcon_dev_register(struct extcon_dev *edev, struct device *dev) | |||
714 | goto err_alloc_groups; | 714 | goto err_alloc_groups; |
715 | } | 715 | } |
716 | 716 | ||
717 | edev->extcon_dev_type.name = dev_name(edev->dev); | 717 | edev->extcon_dev_type.name = dev_name(&edev->dev); |
718 | edev->extcon_dev_type.release = dummy_sysfs_dev_release; | 718 | edev->extcon_dev_type.release = dummy_sysfs_dev_release; |
719 | 719 | ||
720 | for (index = 0; index < edev->max_supported; index++) | 720 | for (index = 0; index < edev->max_supported; index++) |
@@ -724,25 +724,24 @@ int extcon_dev_register(struct extcon_dev *edev, struct device *dev) | |||
724 | edev->extcon_dev_type.groups[index] = | 724 | edev->extcon_dev_type.groups[index] = |
725 | &edev->attr_g_muex; | 725 | &edev->attr_g_muex; |
726 | 726 | ||
727 | edev->dev->type = &edev->extcon_dev_type; | 727 | edev->dev.type = &edev->extcon_dev_type; |
728 | } | 728 | } |
729 | 729 | ||
730 | ret = device_register(edev->dev); | 730 | ret = device_register(&edev->dev); |
731 | if (ret) { | 731 | if (ret) { |
732 | put_device(edev->dev); | 732 | put_device(&edev->dev); |
733 | goto err_dev; | 733 | goto err_dev; |
734 | } | 734 | } |
735 | #if defined(CONFIG_ANDROID) | 735 | #if defined(CONFIG_ANDROID) |
736 | if (switch_class) | 736 | if (switch_class) |
737 | ret = class_compat_create_link(switch_class, edev->dev, | 737 | ret = class_compat_create_link(switch_class, &edev->dev, NULL); |
738 | NULL); | ||
739 | #endif /* CONFIG_ANDROID */ | 738 | #endif /* CONFIG_ANDROID */ |
740 | 739 | ||
741 | spin_lock_init(&edev->lock); | 740 | spin_lock_init(&edev->lock); |
742 | 741 | ||
743 | RAW_INIT_NOTIFIER_HEAD(&edev->nh); | 742 | RAW_INIT_NOTIFIER_HEAD(&edev->nh); |
744 | 743 | ||
745 | dev_set_drvdata(edev->dev, edev); | 744 | dev_set_drvdata(&edev->dev, edev); |
746 | edev->state = 0; | 745 | edev->state = 0; |
747 | 746 | ||
748 | mutex_lock(&extcon_dev_list_lock); | 747 | mutex_lock(&extcon_dev_list_lock); |
@@ -768,7 +767,6 @@ err_alloc_cables: | |||
768 | if (edev->max_supported) | 767 | if (edev->max_supported) |
769 | kfree(edev->cables); | 768 | kfree(edev->cables); |
770 | err_sysfs_alloc: | 769 | err_sysfs_alloc: |
771 | kfree(edev->dev); | ||
772 | return ret; | 770 | return ret; |
773 | } | 771 | } |
774 | EXPORT_SYMBOL_GPL(extcon_dev_register); | 772 | EXPORT_SYMBOL_GPL(extcon_dev_register); |
@@ -788,9 +786,9 @@ void extcon_dev_unregister(struct extcon_dev *edev) | |||
788 | list_del(&edev->entry); | 786 | list_del(&edev->entry); |
789 | mutex_unlock(&extcon_dev_list_lock); | 787 | mutex_unlock(&extcon_dev_list_lock); |
790 | 788 | ||
791 | if (IS_ERR_OR_NULL(get_device(edev->dev))) { | 789 | if (IS_ERR_OR_NULL(get_device(&edev->dev))) { |
792 | dev_err(edev->dev, "Failed to unregister extcon_dev (%s)\n", | 790 | dev_err(&edev->dev, "Failed to unregister extcon_dev (%s)\n", |
793 | dev_name(edev->dev)); | 791 | dev_name(&edev->dev)); |
794 | return; | 792 | return; |
795 | } | 793 | } |
796 | 794 | ||
@@ -812,10 +810,10 @@ void extcon_dev_unregister(struct extcon_dev *edev) | |||
812 | 810 | ||
813 | #if defined(CONFIG_ANDROID) | 811 | #if defined(CONFIG_ANDROID) |
814 | if (switch_class) | 812 | if (switch_class) |
815 | class_compat_remove_link(switch_class, edev->dev, NULL); | 813 | class_compat_remove_link(switch_class, &edev->dev, NULL); |
816 | #endif | 814 | #endif |
817 | device_unregister(edev->dev); | 815 | device_unregister(&edev->dev); |
818 | put_device(edev->dev); | 816 | put_device(&edev->dev); |
819 | } | 817 | } |
820 | EXPORT_SYMBOL_GPL(extcon_dev_unregister); | 818 | EXPORT_SYMBOL_GPL(extcon_dev_unregister); |
821 | 819 | ||
diff --git a/drivers/extcon/extcon-gpio.c b/drivers/extcon/extcon-gpio.c index f874c30ddbff..7e0dff58e494 100644 --- a/drivers/extcon/extcon-gpio.c +++ b/drivers/extcon/extcon-gpio.c | |||
@@ -34,6 +34,7 @@ | |||
34 | struct gpio_extcon_data { | 34 | struct gpio_extcon_data { |
35 | struct extcon_dev edev; | 35 | struct extcon_dev edev; |
36 | unsigned gpio; | 36 | unsigned gpio; |
37 | bool gpio_active_low; | ||
37 | const char *state_on; | 38 | const char *state_on; |
38 | const char *state_off; | 39 | const char *state_off; |
39 | int irq; | 40 | int irq; |
@@ -49,6 +50,8 @@ static void gpio_extcon_work(struct work_struct *work) | |||
49 | work); | 50 | work); |
50 | 51 | ||
51 | state = gpio_get_value(data->gpio); | 52 | state = gpio_get_value(data->gpio); |
53 | if (data->gpio_active_low) | ||
54 | state = !state; | ||
52 | extcon_set_state(&data->edev, state); | 55 | extcon_set_state(&data->edev, state); |
53 | } | 56 | } |
54 | 57 | ||
@@ -78,9 +81,9 @@ static ssize_t extcon_gpio_print_state(struct extcon_dev *edev, char *buf) | |||
78 | 81 | ||
79 | static int gpio_extcon_probe(struct platform_device *pdev) | 82 | static int gpio_extcon_probe(struct platform_device *pdev) |
80 | { | 83 | { |
81 | struct gpio_extcon_platform_data *pdata = pdev->dev.platform_data; | 84 | struct gpio_extcon_platform_data *pdata = dev_get_platdata(&pdev->dev); |
82 | struct gpio_extcon_data *extcon_data; | 85 | struct gpio_extcon_data *extcon_data; |
83 | int ret = 0; | 86 | int ret; |
84 | 87 | ||
85 | if (!pdata) | 88 | if (!pdata) |
86 | return -EBUSY; | 89 | return -EBUSY; |
@@ -95,14 +98,22 @@ static int gpio_extcon_probe(struct platform_device *pdev) | |||
95 | return -ENOMEM; | 98 | return -ENOMEM; |
96 | 99 | ||
97 | extcon_data->edev.name = pdata->name; | 100 | extcon_data->edev.name = pdata->name; |
101 | extcon_data->edev.dev.parent = &pdev->dev; | ||
98 | extcon_data->gpio = pdata->gpio; | 102 | extcon_data->gpio = pdata->gpio; |
103 | extcon_data->gpio_active_low = pdata->gpio_active_low; | ||
99 | extcon_data->state_on = pdata->state_on; | 104 | extcon_data->state_on = pdata->state_on; |
100 | extcon_data->state_off = pdata->state_off; | 105 | extcon_data->state_off = pdata->state_off; |
101 | if (pdata->state_on && pdata->state_off) | 106 | if (pdata->state_on && pdata->state_off) |
102 | extcon_data->edev.print_state = extcon_gpio_print_state; | 107 | extcon_data->edev.print_state = extcon_gpio_print_state; |
103 | extcon_data->debounce_jiffies = msecs_to_jiffies(pdata->debounce); | 108 | if (pdata->debounce) { |
109 | ret = gpio_set_debounce(extcon_data->gpio, | ||
110 | pdata->debounce * 1000); | ||
111 | if (ret < 0) | ||
112 | extcon_data->debounce_jiffies = | ||
113 | msecs_to_jiffies(pdata->debounce); | ||
114 | } | ||
104 | 115 | ||
105 | ret = extcon_dev_register(&extcon_data->edev, &pdev->dev); | 116 | ret = extcon_dev_register(&extcon_data->edev); |
106 | if (ret < 0) | 117 | if (ret < 0) |
107 | return ret; | 118 | return ret; |
108 | 119 | ||
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c index b56bdaa27d4b..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 | ||
@@ -953,7 +965,7 @@ static void max77693_muic_irq_work(struct work_struct *work) | |||
953 | 965 | ||
954 | mutex_lock(&info->mutex); | 966 | mutex_lock(&info->mutex); |
955 | 967 | ||
956 | for (i = 0 ; i < ARRAY_SIZE(muic_irqs) ; i++) | 968 | for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) |
957 | if (info->irq == muic_irqs[i].virq) | 969 | if (info->irq == muic_irqs[i].virq) |
958 | irq_type = muic_irqs[i].irq; | 970 | irq_type = muic_irqs[i].irq; |
959 | 971 | ||
@@ -1171,8 +1183,9 @@ static int max77693_muic_probe(struct platform_device *pdev) | |||
1171 | goto err_irq; | 1183 | goto err_irq; |
1172 | } | 1184 | } |
1173 | info->edev->name = DEV_NAME; | 1185 | info->edev->name = DEV_NAME; |
1186 | info->edev->dev.parent = &pdev->dev; | ||
1174 | info->edev->supported_cable = max77693_extcon_cable; | 1187 | info->edev->supported_cable = max77693_extcon_cable; |
1175 | ret = extcon_dev_register(info->edev, NULL); | 1188 | ret = extcon_dev_register(info->edev); |
1176 | if (ret) { | 1189 | if (ret) { |
1177 | dev_err(&pdev->dev, "failed to register extcon device\n"); | 1190 | dev_err(&pdev->dev, "failed to register extcon device\n"); |
1178 | goto err_irq; | 1191 | goto err_irq; |
@@ -1188,7 +1201,7 @@ static int max77693_muic_probe(struct platform_device *pdev) | |||
1188 | num_init_data = ARRAY_SIZE(default_init_data); | 1201 | num_init_data = ARRAY_SIZE(default_init_data); |
1189 | } | 1202 | } |
1190 | 1203 | ||
1191 | for (i = 0 ; i < num_init_data ; i++) { | 1204 | for (i = 0; i < num_init_data; i++) { |
1192 | enum max77693_irq_source irq_src | 1205 | enum max77693_irq_source irq_src |
1193 | = MAX77693_IRQ_GROUP_NR; | 1206 | = MAX77693_IRQ_GROUP_NR; |
1194 | 1207 | ||
@@ -1214,7 +1227,8 @@ static int max77693_muic_probe(struct platform_device *pdev) | |||
1214 | } | 1227 | } |
1215 | 1228 | ||
1216 | if (pdata->muic_data) { | 1229 | if (pdata->muic_data) { |
1217 | struct max77693_muic_platform_data *muic_pdata = pdata->muic_data; | 1230 | struct max77693_muic_platform_data *muic_pdata |
1231 | = pdata->muic_data; | ||
1218 | 1232 | ||
1219 | /* | 1233 | /* |
1220 | * 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 67d6738d85a0..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); |
@@ -537,7 +539,7 @@ static void max8997_muic_irq_work(struct work_struct *work) | |||
537 | 539 | ||
538 | mutex_lock(&info->mutex); | 540 | mutex_lock(&info->mutex); |
539 | 541 | ||
540 | for (i = 0 ; i < ARRAY_SIZE(muic_irqs) ; i++) | 542 | for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) |
541 | if (info->irq == muic_irqs[i].virq) | 543 | if (info->irq == muic_irqs[i].virq) |
542 | irq_type = muic_irqs[i].irq; | 544 | irq_type = muic_irqs[i].irq; |
543 | 545 | ||
@@ -705,8 +707,9 @@ static int max8997_muic_probe(struct platform_device *pdev) | |||
705 | goto err_irq; | 707 | goto err_irq; |
706 | } | 708 | } |
707 | info->edev->name = DEV_NAME; | 709 | info->edev->name = DEV_NAME; |
710 | info->edev->dev.parent = &pdev->dev; | ||
708 | info->edev->supported_cable = max8997_extcon_cable; | 711 | info->edev->supported_cable = max8997_extcon_cable; |
709 | ret = extcon_dev_register(info->edev, NULL); | 712 | ret = extcon_dev_register(info->edev); |
710 | if (ret) { | 713 | if (ret) { |
711 | dev_err(&pdev->dev, "failed to register extcon device\n"); | 714 | dev_err(&pdev->dev, "failed to register extcon device\n"); |
712 | goto err_irq; | 715 | goto err_irq; |
diff --git a/drivers/extcon/extcon-palmas.c b/drivers/extcon/extcon-palmas.c index 89fdd05c5fd6..6c91976dd823 100644 --- a/drivers/extcon/extcon-palmas.c +++ b/drivers/extcon/extcon-palmas.c | |||
@@ -135,7 +135,7 @@ static void palmas_enable_irq(struct palmas_usb *palmas_usb) | |||
135 | static int palmas_usb_probe(struct platform_device *pdev) | 135 | static int palmas_usb_probe(struct platform_device *pdev) |
136 | { | 136 | { |
137 | struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); | 137 | struct palmas *palmas = dev_get_drvdata(pdev->dev.parent); |
138 | struct palmas_usb_platform_data *pdata = pdev->dev.platform_data; | 138 | struct palmas_usb_platform_data *pdata = dev_get_platdata(&pdev->dev); |
139 | struct device_node *node = pdev->dev.of_node; | 139 | struct device_node *node = pdev->dev.of_node; |
140 | struct palmas_usb *palmas_usb; | 140 | struct palmas_usb *palmas_usb; |
141 | int status; | 141 | int status; |
@@ -178,9 +178,10 @@ static int palmas_usb_probe(struct platform_device *pdev) | |||
178 | platform_set_drvdata(pdev, palmas_usb); | 178 | platform_set_drvdata(pdev, palmas_usb); |
179 | 179 | ||
180 | palmas_usb->edev.supported_cable = palmas_extcon_cable; | 180 | palmas_usb->edev.supported_cable = palmas_extcon_cable; |
181 | palmas_usb->edev.dev.parent = palmas_usb->dev; | ||
181 | palmas_usb->edev.mutually_exclusive = mutually_exclusive; | 182 | palmas_usb->edev.mutually_exclusive = mutually_exclusive; |
182 | 183 | ||
183 | status = extcon_dev_register(&palmas_usb->edev, palmas_usb->dev); | 184 | status = extcon_dev_register(&palmas_usb->edev); |
184 | if (status) { | 185 | if (status) { |
185 | dev_err(&pdev->dev, "failed to register extcon device\n"); | 186 | dev_err(&pdev->dev, "failed to register extcon device\n"); |
186 | return status; | 187 | return status; |
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/channel_mgmt.c b/drivers/hv/channel_mgmt.c index bbff5f200bef..fa920469bf10 100644 --- a/drivers/hv/channel_mgmt.c +++ b/drivers/hv/channel_mgmt.c | |||
@@ -203,7 +203,8 @@ static void vmbus_process_rescind_offer(struct work_struct *work) | |||
203 | struct vmbus_channel *primary_channel; | 203 | struct vmbus_channel *primary_channel; |
204 | struct vmbus_channel_relid_released msg; | 204 | struct vmbus_channel_relid_released msg; |
205 | 205 | ||
206 | vmbus_device_unregister(channel->device_obj); | 206 | if (channel->device_obj) |
207 | vmbus_device_unregister(channel->device_obj); | ||
207 | memset(&msg, 0, sizeof(struct vmbus_channel_relid_released)); | 208 | memset(&msg, 0, sizeof(struct vmbus_channel_relid_released)); |
208 | msg.child_relid = channel->offermsg.child_relid; | 209 | msg.child_relid = channel->offermsg.child_relid; |
209 | msg.header.msgtype = CHANNELMSG_RELID_RELEASED; | 210 | msg.header.msgtype = CHANNELMSG_RELID_RELEASED; |
@@ -216,7 +217,7 @@ static void vmbus_process_rescind_offer(struct work_struct *work) | |||
216 | } else { | 217 | } else { |
217 | primary_channel = channel->primary_channel; | 218 | primary_channel = channel->primary_channel; |
218 | spin_lock_irqsave(&primary_channel->sc_lock, flags); | 219 | spin_lock_irqsave(&primary_channel->sc_lock, flags); |
219 | list_del(&channel->listentry); | 220 | list_del(&channel->sc_list); |
220 | spin_unlock_irqrestore(&primary_channel->sc_lock, flags); | 221 | spin_unlock_irqrestore(&primary_channel->sc_lock, flags); |
221 | } | 222 | } |
222 | free_channel(channel); | 223 | free_channel(channel); |
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index 936093e0271e..af6edf9b1936 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.c b/drivers/hv/hv.c index 88f4096fa078..f0c5e07c25ec 100644 --- a/drivers/hv/hv.c +++ b/drivers/hv/hv.c | |||
@@ -304,7 +304,7 @@ err: | |||
304 | void hv_synic_free_cpu(int cpu) | 304 | void hv_synic_free_cpu(int cpu) |
305 | { | 305 | { |
306 | kfree(hv_context.event_dpc[cpu]); | 306 | kfree(hv_context.event_dpc[cpu]); |
307 | if (hv_context.synic_message_page[cpu]) | 307 | if (hv_context.synic_event_page[cpu]) |
308 | free_page((unsigned long)hv_context.synic_event_page[cpu]); | 308 | free_page((unsigned long)hv_context.synic_event_page[cpu]); |
309 | if (hv_context.synic_message_page[cpu]) | 309 | if (hv_context.synic_message_page[cpu]) |
310 | free_page((unsigned long)hv_context.synic_message_page[cpu]); | 310 | free_page((unsigned long)hv_context.synic_message_page[cpu]); |
diff --git a/drivers/hv/hv_util.c b/drivers/hv/hv_util.c index 273e3ddb3a20..62dfd246b948 100644 --- a/drivers/hv/hv_util.c +++ b/drivers/hv/hv_util.c | |||
@@ -97,7 +97,7 @@ static void shutdown_onchannelcallback(void *context) | |||
97 | struct vmbus_channel *channel = context; | 97 | struct vmbus_channel *channel = context; |
98 | u32 recvlen; | 98 | u32 recvlen; |
99 | u64 requestid; | 99 | u64 requestid; |
100 | u8 execute_shutdown = false; | 100 | bool execute_shutdown = false; |
101 | u8 *shut_txf_buf = util_shutdown.recv_buffer; | 101 | u8 *shut_txf_buf = util_shutdown.recv_buffer; |
102 | 102 | ||
103 | struct shutdown_msg_data *shutdown_msg; | 103 | 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/arm-charlcd.c b/drivers/misc/arm-charlcd.c index 1256a4bf1c04..b7ebf8021d99 100644 --- a/drivers/misc/arm-charlcd.c +++ b/drivers/misc/arm-charlcd.c | |||
@@ -297,7 +297,7 @@ static int __init charlcd_probe(struct platform_device *pdev) | |||
297 | lcd->irq = platform_get_irq(pdev, 0); | 297 | lcd->irq = platform_get_irq(pdev, 0); |
298 | /* If no IRQ is supplied, we'll survive without it */ | 298 | /* If no IRQ is supplied, we'll survive without it */ |
299 | if (lcd->irq >= 0) { | 299 | if (lcd->irq >= 0) { |
300 | if (request_irq(lcd->irq, charlcd_interrupt, IRQF_DISABLED, | 300 | if (request_irq(lcd->irq, charlcd_interrupt, 0, |
301 | DRIVERNAME, lcd)) { | 301 | DRIVERNAME, lcd)) { |
302 | ret = -EIO; | 302 | ret = -EIO; |
303 | goto out_no_irq; | 303 | goto out_no_irq; |
diff --git a/drivers/misc/atmel_pwm.c b/drivers/misc/atmel_pwm.c index 494d0500bda6..a6dc56e1bc58 100644 --- a/drivers/misc/atmel_pwm.c +++ b/drivers/misc/atmel_pwm.c | |||
@@ -90,8 +90,10 @@ int pwm_channel_alloc(int index, struct pwm_channel *ch) | |||
90 | unsigned long flags; | 90 | unsigned long flags; |
91 | int status = 0; | 91 | int status = 0; |
92 | 92 | ||
93 | /* insist on PWM init, with this signal pinned out */ | 93 | if (!pwm) |
94 | if (!pwm || !(pwm->mask & 1 << index)) | 94 | return -EPROBE_DEFER; |
95 | |||
96 | if (!(pwm->mask & 1 << index)) | ||
95 | return -ENODEV; | 97 | return -ENODEV; |
96 | 98 | ||
97 | if (index < 0 || index >= PWM_NCHAN || !ch) | 99 | if (index < 0 || index >= PWM_NCHAN || !ch) |
diff --git a/drivers/misc/bh1780gli.c b/drivers/misc/bh1780gli.c index 057580e026c0..48ea33d15a79 100644 --- a/drivers/misc/bh1780gli.c +++ b/drivers/misc/bh1780gli.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/of.h> | ||
26 | 27 | ||
27 | #define BH1780_REG_CONTROL 0x80 | 28 | #define BH1780_REG_CONTROL 0x80 |
28 | #define BH1780_REG_PARTID 0x8A | 29 | #define BH1780_REG_PARTID 0x8A |
@@ -244,6 +245,15 @@ static const struct i2c_device_id bh1780_id[] = { | |||
244 | { }, | 245 | { }, |
245 | }; | 246 | }; |
246 | 247 | ||
248 | #ifdef CONFIG_OF | ||
249 | static const struct of_device_id of_bh1780_match[] = { | ||
250 | { .compatible = "rohm,bh1780gli", }, | ||
251 | {}, | ||
252 | }; | ||
253 | |||
254 | MODULE_DEVICE_TABLE(of, of_bh1780_match); | ||
255 | #endif | ||
256 | |||
247 | static struct i2c_driver bh1780_driver = { | 257 | static struct i2c_driver bh1780_driver = { |
248 | .probe = bh1780_probe, | 258 | .probe = bh1780_probe, |
249 | .remove = bh1780_remove, | 259 | .remove = bh1780_remove, |
@@ -251,6 +261,7 @@ static struct i2c_driver bh1780_driver = { | |||
251 | .driver = { | 261 | .driver = { |
252 | .name = "bh1780", | 262 | .name = "bh1780", |
253 | .pm = &bh1780_pm, | 263 | .pm = &bh1780_pm, |
264 | .of_match_table = of_match_ptr(of_bh1780_match), | ||
254 | }, | 265 | }, |
255 | }; | 266 | }; |
256 | 267 | ||
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/at24.c b/drivers/misc/eeprom/at24.c index 5d4fd69d04ca..94b8a3324319 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c | |||
@@ -428,6 +428,9 @@ static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj, | |||
428 | { | 428 | { |
429 | struct at24_data *at24; | 429 | struct at24_data *at24; |
430 | 430 | ||
431 | if (unlikely(off >= attr->size)) | ||
432 | return -EFBIG; | ||
433 | |||
431 | at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); | 434 | at24 = dev_get_drvdata(container_of(kobj, struct device, kobj)); |
432 | return at24_write(at24, buf, off, count); | 435 | return at24_write(at24, buf, off, count); |
433 | } | 436 | } |
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c index 840b3594a5ae..4f3bca1003a1 100644 --- a/drivers/misc/eeprom/at25.c +++ b/drivers/misc/eeprom/at25.c | |||
@@ -462,10 +462,17 @@ static int at25_remove(struct spi_device *spi) | |||
462 | 462 | ||
463 | /*-------------------------------------------------------------------------*/ | 463 | /*-------------------------------------------------------------------------*/ |
464 | 464 | ||
465 | static const struct of_device_id at25_of_match[] = { | ||
466 | { .compatible = "atmel,at25", }, | ||
467 | { } | ||
468 | }; | ||
469 | MODULE_DEVICE_TABLE(of, at25_of_match); | ||
470 | |||
465 | static struct spi_driver at25_driver = { | 471 | static struct spi_driver at25_driver = { |
466 | .driver = { | 472 | .driver = { |
467 | .name = "at25", | 473 | .name = "at25", |
468 | .owner = THIS_MODULE, | 474 | .owner = THIS_MODULE, |
475 | .of_match_table = at25_of_match, | ||
469 | }, | 476 | }, |
470 | .probe = at25_probe, | 477 | .probe = at25_probe, |
471 | .remove = at25_remove, | 478 | .remove = at25_remove, |
diff --git a/drivers/misc/eeprom/eeprom_93xx46.c b/drivers/misc/eeprom/eeprom_93xx46.c index 94cfc1212577..3a015abb444a 100644 --- a/drivers/misc/eeprom/eeprom_93xx46.c +++ b/drivers/misc/eeprom/eeprom_93xx46.c | |||
@@ -202,7 +202,7 @@ eeprom_93xx46_bin_write(struct file *filp, struct kobject *kobj, | |||
202 | edev = dev_get_drvdata(dev); | 202 | edev = dev_get_drvdata(dev); |
203 | 203 | ||
204 | if (unlikely(off >= edev->bin.size)) | 204 | if (unlikely(off >= edev->bin.size)) |
205 | return 0; | 205 | return -EFBIG; |
206 | if ((off + count) > edev->bin.size) | 206 | if ((off + count) > edev->bin.size) |
207 | count = edev->bin.size - off; | 207 | count = edev->bin.size - off; |
208 | if (unlikely(!count)) | 208 | if (unlikely(!count)) |
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/lkdtm.c b/drivers/misc/lkdtm.c index 2fc0586ce3bb..a2edb2ee0921 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c | |||
@@ -44,13 +44,25 @@ | |||
44 | #include <scsi/scsi_cmnd.h> | 44 | #include <scsi/scsi_cmnd.h> |
45 | #include <linux/debugfs.h> | 45 | #include <linux/debugfs.h> |
46 | #include <linux/vmalloc.h> | 46 | #include <linux/vmalloc.h> |
47 | #include <linux/mman.h> | ||
47 | 48 | ||
48 | #ifdef CONFIG_IDE | 49 | #ifdef CONFIG_IDE |
49 | #include <linux/ide.h> | 50 | #include <linux/ide.h> |
50 | #endif | 51 | #endif |
51 | 52 | ||
53 | /* | ||
54 | * Make sure our attempts to over run the kernel stack doesn't trigger | ||
55 | * a compiler warning when CONFIG_FRAME_WARN is set. Then make sure we | ||
56 | * recurse past the end of THREAD_SIZE by default. | ||
57 | */ | ||
58 | #if defined(CONFIG_FRAME_WARN) && (CONFIG_FRAME_WARN > 0) | ||
59 | #define REC_STACK_SIZE (CONFIG_FRAME_WARN / 2) | ||
60 | #else | ||
61 | #define REC_STACK_SIZE (THREAD_SIZE / 8) | ||
62 | #endif | ||
63 | #define REC_NUM_DEFAULT ((THREAD_SIZE / REC_STACK_SIZE) * 2) | ||
64 | |||
52 | #define DEFAULT_COUNT 10 | 65 | #define DEFAULT_COUNT 10 |
53 | #define REC_NUM_DEFAULT 10 | ||
54 | #define EXEC_SIZE 64 | 66 | #define EXEC_SIZE 64 |
55 | 67 | ||
56 | enum cname { | 68 | enum cname { |
@@ -86,6 +98,9 @@ enum ctype { | |||
86 | CT_EXEC_STACK, | 98 | CT_EXEC_STACK, |
87 | CT_EXEC_KMALLOC, | 99 | CT_EXEC_KMALLOC, |
88 | CT_EXEC_VMALLOC, | 100 | CT_EXEC_VMALLOC, |
101 | CT_EXEC_USERSPACE, | ||
102 | CT_ACCESS_USERSPACE, | ||
103 | CT_WRITE_RO, | ||
89 | }; | 104 | }; |
90 | 105 | ||
91 | static char* cp_name[] = { | 106 | static char* cp_name[] = { |
@@ -119,6 +134,9 @@ static char* cp_type[] = { | |||
119 | "EXEC_STACK", | 134 | "EXEC_STACK", |
120 | "EXEC_KMALLOC", | 135 | "EXEC_KMALLOC", |
121 | "EXEC_VMALLOC", | 136 | "EXEC_VMALLOC", |
137 | "EXEC_USERSPACE", | ||
138 | "ACCESS_USERSPACE", | ||
139 | "WRITE_RO", | ||
122 | }; | 140 | }; |
123 | 141 | ||
124 | static struct jprobe lkdtm; | 142 | static struct jprobe lkdtm; |
@@ -139,9 +157,10 @@ static DEFINE_SPINLOCK(lock_me_up); | |||
139 | 157 | ||
140 | static u8 data_area[EXEC_SIZE]; | 158 | static u8 data_area[EXEC_SIZE]; |
141 | 159 | ||
160 | static const unsigned long rodata = 0xAA55AA55; | ||
161 | |||
142 | module_param(recur_count, int, 0644); | 162 | module_param(recur_count, int, 0644); |
143 | MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test, "\ | 163 | MODULE_PARM_DESC(recur_count, " Recursion level for the stack overflow test"); |
144 | "default is 10"); | ||
145 | module_param(cpoint_name, charp, 0444); | 164 | module_param(cpoint_name, charp, 0444); |
146 | MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); | 165 | MODULE_PARM_DESC(cpoint_name, " Crash Point, where kernel is to be crashed"); |
147 | module_param(cpoint_type, charp, 0444); | 166 | module_param(cpoint_type, charp, 0444); |
@@ -280,16 +299,16 @@ static int lkdtm_parse_commandline(void) | |||
280 | return -EINVAL; | 299 | return -EINVAL; |
281 | } | 300 | } |
282 | 301 | ||
283 | static int recursive_loop(int a) | 302 | static int recursive_loop(int remaining) |
284 | { | 303 | { |
285 | char buf[1024]; | 304 | char buf[REC_STACK_SIZE]; |
286 | 305 | ||
287 | memset(buf,0xFF,1024); | 306 | /* Make sure compiler does not optimize this away. */ |
288 | recur_count--; | 307 | memset(buf, (remaining & 0xff) | 0x1, REC_STACK_SIZE); |
289 | if (!recur_count) | 308 | if (!remaining) |
290 | return 0; | 309 | return 0; |
291 | else | 310 | else |
292 | return recursive_loop(a); | 311 | return recursive_loop(remaining - 1); |
293 | } | 312 | } |
294 | 313 | ||
295 | static void do_nothing(void) | 314 | static void do_nothing(void) |
@@ -297,6 +316,14 @@ static void do_nothing(void) | |||
297 | return; | 316 | return; |
298 | } | 317 | } |
299 | 318 | ||
319 | static noinline void corrupt_stack(void) | ||
320 | { | ||
321 | /* Use default char array length that triggers stack protection. */ | ||
322 | char data[8]; | ||
323 | |||
324 | memset((void *)data, 0, 64); | ||
325 | } | ||
326 | |||
300 | static void execute_location(void *dst) | 327 | static void execute_location(void *dst) |
301 | { | 328 | { |
302 | void (*func)(void) = dst; | 329 | void (*func)(void) = dst; |
@@ -305,6 +332,15 @@ static void execute_location(void *dst) | |||
305 | func(); | 332 | func(); |
306 | } | 333 | } |
307 | 334 | ||
335 | static void execute_user_location(void *dst) | ||
336 | { | ||
337 | void (*func)(void) = dst; | ||
338 | |||
339 | if (copy_to_user(dst, do_nothing, EXEC_SIZE)) | ||
340 | return; | ||
341 | func(); | ||
342 | } | ||
343 | |||
308 | static void lkdtm_do_action(enum ctype which) | 344 | static void lkdtm_do_action(enum ctype which) |
309 | { | 345 | { |
310 | switch (which) { | 346 | switch (which) { |
@@ -325,15 +361,11 @@ static void lkdtm_do_action(enum ctype which) | |||
325 | ; | 361 | ; |
326 | break; | 362 | break; |
327 | case CT_OVERFLOW: | 363 | case CT_OVERFLOW: |
328 | (void) recursive_loop(0); | 364 | (void) recursive_loop(recur_count); |
329 | break; | 365 | break; |
330 | case CT_CORRUPT_STACK: { | 366 | case CT_CORRUPT_STACK: |
331 | /* Make sure the compiler creates and uses an 8 char array. */ | 367 | corrupt_stack(); |
332 | volatile char data[8]; | ||
333 | |||
334 | memset((void *)data, 0, 64); | ||
335 | break; | 368 | break; |
336 | } | ||
337 | case CT_UNALIGNED_LOAD_STORE_WRITE: { | 369 | case CT_UNALIGNED_LOAD_STORE_WRITE: { |
338 | static u8 data[5] __attribute__((aligned(4))) = {1, 2, | 370 | static u8 data[5] __attribute__((aligned(4))) = {1, 2, |
339 | 3, 4, 5}; | 371 | 3, 4, 5}; |
@@ -401,6 +433,49 @@ static void lkdtm_do_action(enum ctype which) | |||
401 | vfree(vmalloc_area); | 433 | vfree(vmalloc_area); |
402 | break; | 434 | break; |
403 | } | 435 | } |
436 | case CT_EXEC_USERSPACE: { | ||
437 | unsigned long user_addr; | ||
438 | |||
439 | user_addr = vm_mmap(NULL, 0, PAGE_SIZE, | ||
440 | PROT_READ | PROT_WRITE | PROT_EXEC, | ||
441 | MAP_ANONYMOUS | MAP_PRIVATE, 0); | ||
442 | if (user_addr >= TASK_SIZE) { | ||
443 | pr_warn("Failed to allocate user memory\n"); | ||
444 | return; | ||
445 | } | ||
446 | execute_user_location((void *)user_addr); | ||
447 | vm_munmap(user_addr, PAGE_SIZE); | ||
448 | break; | ||
449 | } | ||
450 | case CT_ACCESS_USERSPACE: { | ||
451 | unsigned long user_addr, tmp; | ||
452 | unsigned long *ptr; | ||
453 | |||
454 | user_addr = vm_mmap(NULL, 0, PAGE_SIZE, | ||
455 | PROT_READ | PROT_WRITE | PROT_EXEC, | ||
456 | MAP_ANONYMOUS | MAP_PRIVATE, 0); | ||
457 | if (user_addr >= TASK_SIZE) { | ||
458 | pr_warn("Failed to allocate user memory\n"); | ||
459 | return; | ||
460 | } | ||
461 | |||
462 | ptr = (unsigned long *)user_addr; | ||
463 | tmp = *ptr; | ||
464 | tmp += 0xc0dec0de; | ||
465 | *ptr = tmp; | ||
466 | |||
467 | vm_munmap(user_addr, PAGE_SIZE); | ||
468 | |||
469 | break; | ||
470 | } | ||
471 | case CT_WRITE_RO: { | ||
472 | unsigned long *ptr; | ||
473 | |||
474 | ptr = (unsigned long *)&rodata; | ||
475 | *ptr ^= 0xabcd1234; | ||
476 | |||
477 | break; | ||
478 | } | ||
404 | case CT_NONE: | 479 | case CT_NONE: |
405 | default: | 480 | default: |
406 | break; | 481 | break; |
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c index f6ff711aa5bb..d22c6864508b 100644 --- a/drivers/misc/mei/amthif.c +++ b/drivers/misc/mei/amthif.c | |||
@@ -58,6 +58,7 @@ void mei_amthif_reset_params(struct mei_device *dev) | |||
58 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | 58 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
59 | dev->iamthif_timer = 0; | 59 | dev->iamthif_timer = 0; |
60 | dev->iamthif_stall_timer = 0; | 60 | dev->iamthif_stall_timer = 0; |
61 | dev->iamthif_open_count = 0; | ||
61 | } | 62 | } |
62 | 63 | ||
63 | /** | 64 | /** |
@@ -78,8 +79,10 @@ int mei_amthif_host_init(struct mei_device *dev) | |||
78 | 79 | ||
79 | i = mei_me_cl_by_uuid(dev, &mei_amthif_guid); | 80 | i = mei_me_cl_by_uuid(dev, &mei_amthif_guid); |
80 | if (i < 0) { | 81 | if (i < 0) { |
81 | dev_info(&dev->pdev->dev, "amthif: failed to find the client\n"); | 82 | ret = i; |
82 | return -ENOENT; | 83 | dev_info(&dev->pdev->dev, |
84 | "amthif: failed to find the client %d\n", ret); | ||
85 | return ret; | ||
83 | } | 86 | } |
84 | 87 | ||
85 | cl->me_client_id = dev->me_clients[i].client_id; | 88 | cl->me_client_id = dev->me_clients[i].client_id; |
@@ -106,8 +109,9 @@ int mei_amthif_host_init(struct mei_device *dev) | |||
106 | ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID); | 109 | ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID); |
107 | 110 | ||
108 | if (ret < 0) { | 111 | if (ret < 0) { |
109 | dev_err(&dev->pdev->dev, "amthif: failed link client\n"); | 112 | dev_err(&dev->pdev->dev, |
110 | return -ENOENT; | 113 | "amthif: failed link client %d\n", ret); |
114 | return ret; | ||
111 | } | 115 | } |
112 | 116 | ||
113 | cl->state = MEI_FILE_CONNECTING; | 117 | cl->state = MEI_FILE_CONNECTING; |
@@ -313,13 +317,13 @@ static int mei_amthif_send_cmd(struct mei_device *dev, struct mei_cl_cb *cb) | |||
313 | mei_hdr.me_addr = dev->iamthif_cl.me_client_id; | 317 | mei_hdr.me_addr = dev->iamthif_cl.me_client_id; |
314 | mei_hdr.reserved = 0; | 318 | mei_hdr.reserved = 0; |
315 | dev->iamthif_msg_buf_index += mei_hdr.length; | 319 | dev->iamthif_msg_buf_index += mei_hdr.length; |
316 | if (mei_write_message(dev, &mei_hdr, | 320 | ret = mei_write_message(dev, &mei_hdr, dev->iamthif_msg_buf); |
317 | (unsigned char *)dev->iamthif_msg_buf)) | 321 | if (ret) |
318 | return -ENODEV; | 322 | return ret; |
319 | 323 | ||
320 | if (mei_hdr.msg_complete) { | 324 | if (mei_hdr.msg_complete) { |
321 | if (mei_cl_flow_ctrl_reduce(&dev->iamthif_cl)) | 325 | if (mei_cl_flow_ctrl_reduce(&dev->iamthif_cl)) |
322 | return -ENODEV; | 326 | return -EIO; |
323 | dev->iamthif_flow_control_pending = true; | 327 | dev->iamthif_flow_control_pending = true; |
324 | dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; | 328 | dev->iamthif_state = MEI_IAMTHIF_FLOW_CONTROL; |
325 | dev_dbg(&dev->pdev->dev, "add amthif cb to write waiting list\n"); | 329 | dev_dbg(&dev->pdev->dev, "add amthif cb to write waiting list\n"); |
@@ -459,6 +463,16 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
459 | struct mei_msg_hdr mei_hdr; | 463 | struct mei_msg_hdr mei_hdr; |
460 | size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index; | 464 | size_t len = dev->iamthif_msg_buf_size - dev->iamthif_msg_buf_index; |
461 | u32 msg_slots = mei_data2slots(len); | 465 | u32 msg_slots = mei_data2slots(len); |
466 | int rets; | ||
467 | |||
468 | rets = mei_cl_flow_ctrl_creds(cl); | ||
469 | if (rets < 0) | ||
470 | return rets; | ||
471 | |||
472 | if (rets == 0) { | ||
473 | cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); | ||
474 | return 0; | ||
475 | } | ||
462 | 476 | ||
463 | mei_hdr.host_addr = cl->host_client_id; | 477 | mei_hdr.host_addr = cl->host_client_id; |
464 | mei_hdr.me_addr = cl->me_client_id; | 478 | mei_hdr.me_addr = cl->me_client_id; |
@@ -481,16 +495,17 @@ int mei_amthif_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
481 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr)); | 495 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr)); |
482 | 496 | ||
483 | *slots -= msg_slots; | 497 | *slots -= msg_slots; |
484 | if (mei_write_message(dev, &mei_hdr, | 498 | rets = mei_write_message(dev, &mei_hdr, |
485 | dev->iamthif_msg_buf + dev->iamthif_msg_buf_index)) { | 499 | dev->iamthif_msg_buf + dev->iamthif_msg_buf_index); |
486 | dev->iamthif_state = MEI_IAMTHIF_IDLE; | 500 | if (rets) { |
487 | cl->status = -ENODEV; | 501 | dev->iamthif_state = MEI_IAMTHIF_IDLE; |
488 | list_del(&cb->list); | 502 | cl->status = rets; |
489 | return -ENODEV; | 503 | list_del(&cb->list); |
504 | return rets; | ||
490 | } | 505 | } |
491 | 506 | ||
492 | if (mei_cl_flow_ctrl_reduce(cl)) | 507 | if (mei_cl_flow_ctrl_reduce(cl)) |
493 | return -ENODEV; | 508 | return -EIO; |
494 | 509 | ||
495 | dev->iamthif_msg_buf_index += mei_hdr.length; | 510 | dev->iamthif_msg_buf_index += mei_hdr.length; |
496 | cl->status = 0; | 511 | cl->status = 0; |
@@ -720,8 +735,8 @@ static bool mei_clear_lists(struct mei_device *dev, struct file *file) | |||
720 | */ | 735 | */ |
721 | int mei_amthif_release(struct mei_device *dev, struct file *file) | 736 | int mei_amthif_release(struct mei_device *dev, struct file *file) |
722 | { | 737 | { |
723 | if (dev->open_handle_count > 0) | 738 | if (dev->iamthif_open_count > 0) |
724 | dev->open_handle_count--; | 739 | dev->iamthif_open_count--; |
725 | 740 | ||
726 | if (dev->iamthif_file_object == file && | 741 | if (dev->iamthif_file_object == file && |
727 | dev->iamthif_state != MEI_IAMTHIF_IDLE) { | 742 | dev->iamthif_state != MEI_IAMTHIF_IDLE) { |
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c index cd2033cd7120..4bc7d620d695 100644 --- a/drivers/misc/mei/bus.c +++ b/drivers/misc/mei/bus.c | |||
@@ -245,7 +245,7 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, | |||
245 | /* Check if we have an ME client device */ | 245 | /* Check if we have an ME client device */ |
246 | id = mei_me_cl_by_id(dev, cl->me_client_id); | 246 | id = mei_me_cl_by_id(dev, cl->me_client_id); |
247 | if (id < 0) | 247 | if (id < 0) |
248 | return -ENODEV; | 248 | return id; |
249 | 249 | ||
250 | if (length > dev->me_clients[id].props.max_msg_length) | 250 | if (length > dev->me_clients[id].props.max_msg_length) |
251 | return -EINVAL; | 251 | return -EINVAL; |
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index e0684b4d9a08..87c96e4669e2 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); |
@@ -271,6 +275,7 @@ struct mei_cl_cb *mei_cl_find_read_cb(struct mei_cl *cl) | |||
271 | int mei_cl_link(struct mei_cl *cl, int id) | 275 | int mei_cl_link(struct mei_cl *cl, int id) |
272 | { | 276 | { |
273 | struct mei_device *dev; | 277 | struct mei_device *dev; |
278 | long open_handle_count; | ||
274 | 279 | ||
275 | if (WARN_ON(!cl || !cl->dev)) | 280 | if (WARN_ON(!cl || !cl->dev)) |
276 | return -EINVAL; | 281 | return -EINVAL; |
@@ -284,7 +289,14 @@ int mei_cl_link(struct mei_cl *cl, int id) | |||
284 | 289 | ||
285 | if (id >= MEI_CLIENTS_MAX) { | 290 | if (id >= MEI_CLIENTS_MAX) { |
286 | dev_err(&dev->pdev->dev, "id exceded %d", MEI_CLIENTS_MAX) ; | 291 | dev_err(&dev->pdev->dev, "id exceded %d", MEI_CLIENTS_MAX) ; |
287 | return -ENOENT; | 292 | return -EMFILE; |
293 | } | ||
294 | |||
295 | open_handle_count = dev->open_handle_count + dev->iamthif_open_count; | ||
296 | if (open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { | ||
297 | dev_err(&dev->pdev->dev, "open_handle_count exceded %d", | ||
298 | MEI_MAX_OPEN_HANDLE_COUNT); | ||
299 | return -EMFILE; | ||
288 | } | 300 | } |
289 | 301 | ||
290 | dev->open_handle_count++; | 302 | dev->open_handle_count++; |
@@ -296,7 +308,7 @@ int mei_cl_link(struct mei_cl *cl, int id) | |||
296 | 308 | ||
297 | cl->state = MEI_FILE_INITIALIZING; | 309 | cl->state = MEI_FILE_INITIALIZING; |
298 | 310 | ||
299 | dev_dbg(&dev->pdev->dev, "link cl host id = %d\n", cl->host_client_id); | 311 | cl_dbg(dev, cl, "link cl\n"); |
300 | return 0; | 312 | return 0; |
301 | } | 313 | } |
302 | 314 | ||
@@ -308,7 +320,6 @@ int mei_cl_link(struct mei_cl *cl, int id) | |||
308 | int mei_cl_unlink(struct mei_cl *cl) | 320 | int mei_cl_unlink(struct mei_cl *cl) |
309 | { | 321 | { |
310 | struct mei_device *dev; | 322 | struct mei_device *dev; |
311 | struct mei_cl *pos, *next; | ||
312 | 323 | ||
313 | /* don't shout on error exit path */ | 324 | /* don't shout on error exit path */ |
314 | if (!cl) | 325 | if (!cl) |
@@ -320,14 +331,21 @@ int mei_cl_unlink(struct mei_cl *cl) | |||
320 | 331 | ||
321 | dev = cl->dev; | 332 | dev = cl->dev; |
322 | 333 | ||
323 | list_for_each_entry_safe(pos, next, &dev->file_list, link) { | 334 | cl_dbg(dev, cl, "unlink client"); |
324 | if (cl->host_client_id == pos->host_client_id) { | 335 | |
325 | dev_dbg(&dev->pdev->dev, "remove host client = %d, ME client = %d\n", | 336 | if (dev->open_handle_count > 0) |
326 | pos->host_client_id, pos->me_client_id); | 337 | dev->open_handle_count--; |
327 | list_del_init(&pos->link); | 338 | |
328 | break; | 339 | /* never clear the 0 bit */ |
329 | } | 340 | if (cl->host_client_id) |
330 | } | 341 | clear_bit(cl->host_client_id, dev->host_clients_map); |
342 | |||
343 | list_del_init(&cl->link); | ||
344 | |||
345 | cl->state = MEI_FILE_INITIALIZING; | ||
346 | |||
347 | list_del_init(&cl->link); | ||
348 | |||
331 | return 0; | 349 | return 0; |
332 | } | 350 | } |
333 | 351 | ||
@@ -341,17 +359,6 @@ void mei_host_client_init(struct work_struct *work) | |||
341 | 359 | ||
342 | mutex_lock(&dev->device_lock); | 360 | mutex_lock(&dev->device_lock); |
343 | 361 | ||
344 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); | ||
345 | dev->open_handle_count = 0; | ||
346 | |||
347 | /* | ||
348 | * Reserving the first three client IDs | ||
349 | * 0: Reserved for MEI Bus Message communications | ||
350 | * 1: Reserved for Watchdog | ||
351 | * 2: Reserved for AMTHI | ||
352 | */ | ||
353 | bitmap_set(dev->host_clients_map, 0, 3); | ||
354 | |||
355 | for (i = 0; i < dev->me_clients_num; i++) { | 362 | for (i = 0; i < dev->me_clients_num; i++) { |
356 | client_props = &dev->me_clients[i].props; | 363 | client_props = &dev->me_clients[i].props; |
357 | 364 | ||
@@ -390,6 +397,8 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
390 | 397 | ||
391 | dev = cl->dev; | 398 | dev = cl->dev; |
392 | 399 | ||
400 | cl_dbg(dev, cl, "disconnecting"); | ||
401 | |||
393 | if (cl->state != MEI_FILE_DISCONNECTING) | 402 | if (cl->state != MEI_FILE_DISCONNECTING) |
394 | return 0; | 403 | return 0; |
395 | 404 | ||
@@ -402,13 +411,13 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
402 | dev->hbuf_is_ready = false; | 411 | dev->hbuf_is_ready = false; |
403 | if (mei_hbm_cl_disconnect_req(dev, cl)) { | 412 | if (mei_hbm_cl_disconnect_req(dev, cl)) { |
404 | rets = -ENODEV; | 413 | rets = -ENODEV; |
405 | dev_err(&dev->pdev->dev, "failed to disconnect.\n"); | 414 | cl_err(dev, cl, "failed to disconnect.\n"); |
406 | goto free; | 415 | goto free; |
407 | } | 416 | } |
408 | mdelay(10); /* Wait for hardware disconnection ready */ | 417 | mdelay(10); /* Wait for hardware disconnection ready */ |
409 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); | 418 | list_add_tail(&cb->list, &dev->ctrl_rd_list.list); |
410 | } else { | 419 | } else { |
411 | dev_dbg(&dev->pdev->dev, "add disconnect cb to control write list\n"); | 420 | cl_dbg(dev, cl, "add disconnect cb to control write list\n"); |
412 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); | 421 | list_add_tail(&cb->list, &dev->ctrl_wr_list.list); |
413 | 422 | ||
414 | } | 423 | } |
@@ -421,18 +430,17 @@ int mei_cl_disconnect(struct mei_cl *cl) | |||
421 | mutex_lock(&dev->device_lock); | 430 | mutex_lock(&dev->device_lock); |
422 | if (MEI_FILE_DISCONNECTED == cl->state) { | 431 | if (MEI_FILE_DISCONNECTED == cl->state) { |
423 | rets = 0; | 432 | rets = 0; |
424 | dev_dbg(&dev->pdev->dev, "successfully disconnected from FW client.\n"); | 433 | cl_dbg(dev, cl, "successfully disconnected from FW client.\n"); |
425 | } else { | 434 | } else { |
426 | rets = -ENODEV; | 435 | rets = -ENODEV; |
427 | if (MEI_FILE_DISCONNECTED != cl->state) | 436 | if (MEI_FILE_DISCONNECTED != cl->state) |
428 | dev_dbg(&dev->pdev->dev, "wrong status client disconnect.\n"); | 437 | cl_err(dev, cl, "wrong status client disconnect.\n"); |
429 | 438 | ||
430 | if (err) | 439 | if (err) |
431 | dev_dbg(&dev->pdev->dev, | 440 | cl_dbg(dev, cl, "wait failed disconnect err=%08x\n", |
432 | "wait failed disconnect err=%08x\n", | ||
433 | err); | 441 | err); |
434 | 442 | ||
435 | dev_dbg(&dev->pdev->dev, "failed to disconnect from FW client.\n"); | 443 | cl_err(dev, cl, "failed to disconnect from FW client.\n"); |
436 | } | 444 | } |
437 | 445 | ||
438 | mei_io_list_flush(&dev->ctrl_rd_list, cl); | 446 | mei_io_list_flush(&dev->ctrl_rd_list, cl); |
@@ -639,13 +647,12 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) | |||
639 | return -ENODEV; | 647 | return -ENODEV; |
640 | 648 | ||
641 | if (cl->read_cb) { | 649 | if (cl->read_cb) { |
642 | dev_dbg(&dev->pdev->dev, "read is pending.\n"); | 650 | cl_dbg(dev, cl, "read is pending.\n"); |
643 | return -EBUSY; | 651 | return -EBUSY; |
644 | } | 652 | } |
645 | i = mei_me_cl_by_id(dev, cl->me_client_id); | 653 | i = mei_me_cl_by_id(dev, cl->me_client_id); |
646 | if (i < 0) { | 654 | if (i < 0) { |
647 | dev_err(&dev->pdev->dev, "no such me client %d\n", | 655 | cl_err(dev, cl, "no such me client %d\n", cl->me_client_id); |
648 | cl->me_client_id); | ||
649 | return -ENODEV; | 656 | return -ENODEV; |
650 | } | 657 | } |
651 | 658 | ||
@@ -664,6 +671,7 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) | |||
664 | if (dev->hbuf_is_ready) { | 671 | if (dev->hbuf_is_ready) { |
665 | dev->hbuf_is_ready = false; | 672 | dev->hbuf_is_ready = false; |
666 | if (mei_hbm_cl_flow_control_req(dev, cl)) { | 673 | if (mei_hbm_cl_flow_control_req(dev, cl)) { |
674 | cl_err(dev, cl, "flow control send failed\n"); | ||
667 | rets = -ENODEV; | 675 | rets = -ENODEV; |
668 | goto err; | 676 | goto err; |
669 | } | 677 | } |
@@ -691,10 +699,32 @@ err: | |||
691 | int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | 699 | int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, |
692 | s32 *slots, struct mei_cl_cb *cmpl_list) | 700 | s32 *slots, struct mei_cl_cb *cmpl_list) |
693 | { | 701 | { |
694 | struct mei_device *dev = cl->dev; | 702 | struct mei_device *dev; |
703 | struct mei_msg_data *buf; | ||
695 | struct mei_msg_hdr mei_hdr; | 704 | struct mei_msg_hdr mei_hdr; |
696 | size_t len = cb->request_buffer.size - cb->buf_idx; | 705 | size_t len; |
697 | u32 msg_slots = mei_data2slots(len); | 706 | u32 msg_slots; |
707 | int rets; | ||
708 | |||
709 | |||
710 | if (WARN_ON(!cl || !cl->dev)) | ||
711 | return -ENODEV; | ||
712 | |||
713 | dev = cl->dev; | ||
714 | |||
715 | buf = &cb->request_buffer; | ||
716 | |||
717 | rets = mei_cl_flow_ctrl_creds(cl); | ||
718 | if (rets < 0) | ||
719 | return rets; | ||
720 | |||
721 | if (rets == 0) { | ||
722 | cl_dbg(dev, cl, "No flow control credentials: not sending.\n"); | ||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | len = buf->size - cb->buf_idx; | ||
727 | msg_slots = mei_data2slots(len); | ||
698 | 728 | ||
699 | mei_hdr.host_addr = cl->host_client_id; | 729 | mei_hdr.host_addr = cl->host_client_id; |
700 | mei_hdr.me_addr = cl->me_client_id; | 730 | mei_hdr.me_addr = cl->me_client_id; |
@@ -714,16 +744,15 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
714 | return 0; | 744 | return 0; |
715 | } | 745 | } |
716 | 746 | ||
717 | dev_dbg(&dev->pdev->dev, "buf: size = %d idx = %lu\n", | 747 | cl_dbg(dev, cl, "buf: size = %d idx = %lu\n", |
718 | cb->request_buffer.size, cb->buf_idx); | 748 | cb->request_buffer.size, cb->buf_idx); |
719 | dev_dbg(&dev->pdev->dev, MEI_HDR_FMT, MEI_HDR_PRM(&mei_hdr)); | ||
720 | 749 | ||
721 | *slots -= msg_slots; | 750 | *slots -= msg_slots; |
722 | if (mei_write_message(dev, &mei_hdr, | 751 | rets = mei_write_message(dev, &mei_hdr, buf->data + cb->buf_idx); |
723 | cb->request_buffer.data + cb->buf_idx)) { | 752 | if (rets) { |
724 | cl->status = -ENODEV; | 753 | cl->status = rets; |
725 | list_move_tail(&cb->list, &cmpl_list->list); | 754 | list_move_tail(&cb->list, &cmpl_list->list); |
726 | return -ENODEV; | 755 | return rets; |
727 | } | 756 | } |
728 | 757 | ||
729 | cl->status = 0; | 758 | cl->status = 0; |
@@ -732,7 +761,7 @@ int mei_cl_irq_write_complete(struct mei_cl *cl, struct mei_cl_cb *cb, | |||
732 | 761 | ||
733 | if (mei_hdr.msg_complete) { | 762 | if (mei_hdr.msg_complete) { |
734 | if (mei_cl_flow_ctrl_reduce(cl)) | 763 | if (mei_cl_flow_ctrl_reduce(cl)) |
735 | return -ENODEV; | 764 | return -EIO; |
736 | list_move_tail(&cb->list, &dev->write_waiting_list.list); | 765 | list_move_tail(&cb->list, &dev->write_waiting_list.list); |
737 | } | 766 | } |
738 | 767 | ||
@@ -767,7 +796,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking) | |||
767 | 796 | ||
768 | buf = &cb->request_buffer; | 797 | buf = &cb->request_buffer; |
769 | 798 | ||
770 | dev_dbg(&dev->pdev->dev, "mei_cl_write %d\n", buf->size); | 799 | cl_dbg(dev, cl, "mei_cl_write %d\n", buf->size); |
771 | 800 | ||
772 | 801 | ||
773 | cb->fop_type = MEI_FOP_WRITE; | 802 | cb->fop_type = MEI_FOP_WRITE; |
@@ -800,14 +829,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; | 829 | mei_hdr.me_addr = cl->me_client_id; |
801 | mei_hdr.reserved = 0; | 830 | mei_hdr.reserved = 0; |
802 | 831 | ||
803 | dev_dbg(&dev->pdev->dev, "write " MEI_HDR_FMT "\n", | ||
804 | MEI_HDR_PRM(&mei_hdr)); | ||
805 | |||
806 | 832 | ||
807 | if (mei_write_message(dev, &mei_hdr, buf->data)) { | 833 | rets = mei_write_message(dev, &mei_hdr, buf->data); |
808 | rets = -EIO; | 834 | if (rets) |
809 | goto err; | 835 | goto err; |
810 | } | ||
811 | 836 | ||
812 | cl->writing_state = MEI_WRITING; | 837 | cl->writing_state = MEI_WRITING; |
813 | cb->buf_idx = mei_hdr.length; | 838 | cb->buf_idx = mei_hdr.length; |
@@ -898,11 +923,11 @@ void mei_cl_all_wakeup(struct mei_device *dev) | |||
898 | struct mei_cl *cl, *next; | 923 | struct mei_cl *cl, *next; |
899 | list_for_each_entry_safe(cl, next, &dev->file_list, link) { | 924 | list_for_each_entry_safe(cl, next, &dev->file_list, link) { |
900 | if (waitqueue_active(&cl->rx_wait)) { | 925 | if (waitqueue_active(&cl->rx_wait)) { |
901 | dev_dbg(&dev->pdev->dev, "Waking up reading client!\n"); | 926 | cl_dbg(dev, cl, "Waking up reading client!\n"); |
902 | wake_up_interruptible(&cl->rx_wait); | 927 | wake_up_interruptible(&cl->rx_wait); |
903 | } | 928 | } |
904 | if (waitqueue_active(&cl->tx_wait)) { | 929 | if (waitqueue_active(&cl->tx_wait)) { |
905 | dev_dbg(&dev->pdev->dev, "Waking up writing client!\n"); | 930 | cl_dbg(dev, cl, "Waking up writing client!\n"); |
906 | wake_up_interruptible(&cl->tx_wait); | 931 | wake_up_interruptible(&cl->tx_wait); |
907 | } | 932 | } |
908 | } | 933 | } |
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h index 892cc4207fa2..c8396e582f1c 100644 --- a/drivers/misc/mei/client.h +++ b/drivers/misc/mei/client.h | |||
@@ -115,4 +115,13 @@ void mei_cl_all_disconnect(struct mei_device *dev); | |||
115 | void mei_cl_all_wakeup(struct mei_device *dev); | 115 | void mei_cl_all_wakeup(struct mei_device *dev); |
116 | void mei_cl_all_write_clear(struct mei_device *dev); | 116 | void mei_cl_all_write_clear(struct mei_device *dev); |
117 | 117 | ||
118 | #define MEI_CL_FMT "cl:host=%02d me=%02d " | ||
119 | #define MEI_CL_PRM(cl) (cl)->host_client_id, (cl)->me_client_id | ||
120 | |||
121 | #define cl_dbg(dev, cl, format, arg...) \ | ||
122 | dev_dbg(&(dev)->pdev->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg) | ||
123 | |||
124 | #define cl_err(dev, cl, format, arg...) \ | ||
125 | dev_err(&(dev)->pdev->dev, MEI_CL_FMT format, MEI_CL_PRM(cl), ##arg) | ||
126 | |||
118 | #endif /* _MEI_CLIENT_H_ */ | 127 | #endif /* _MEI_CLIENT_H_ */ |
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c index 0a0448326e9d..9b3a0fb7f265 100644 --- a/drivers/misc/mei/hbm.c +++ b/drivers/misc/mei/hbm.c | |||
@@ -49,7 +49,7 @@ static void mei_hbm_me_cl_allocate(struct mei_device *dev) | |||
49 | kfree(dev->me_clients); | 49 | kfree(dev->me_clients); |
50 | dev->me_clients = NULL; | 50 | dev->me_clients = NULL; |
51 | 51 | ||
52 | dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%zd.\n", | 52 | dev_dbg(&dev->pdev->dev, "memory allocation for ME clients size=%ld.\n", |
53 | dev->me_clients_num * sizeof(struct mei_me_client)); | 53 | dev->me_clients_num * sizeof(struct mei_me_client)); |
54 | /* allocate storage for ME clients representation */ | 54 | /* allocate storage for ME clients representation */ |
55 | clients = kcalloc(dev->me_clients_num, | 55 | clients = kcalloc(dev->me_clients_num, |
@@ -174,7 +174,7 @@ int mei_hbm_start_req(struct mei_device *dev) | |||
174 | dev_err(&dev->pdev->dev, "version message write failed\n"); | 174 | dev_err(&dev->pdev->dev, "version message write failed\n"); |
175 | dev->dev_state = MEI_DEV_RESETTING; | 175 | dev->dev_state = MEI_DEV_RESETTING; |
176 | mei_reset(dev, 1); | 176 | mei_reset(dev, 1); |
177 | return -ENODEV; | 177 | return -EIO; |
178 | } | 178 | } |
179 | dev->hbm_state = MEI_HBM_START; | 179 | dev->hbm_state = MEI_HBM_START; |
180 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; | 180 | dev->init_clients_timer = MEI_CLIENTS_INIT_TIMEOUT; |
@@ -677,7 +677,10 @@ void mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr) | |||
677 | 677 | ||
678 | case HOST_ENUM_RES_CMD: | 678 | case HOST_ENUM_RES_CMD: |
679 | enum_res = (struct hbm_host_enum_response *) mei_msg; | 679 | enum_res = (struct hbm_host_enum_response *) mei_msg; |
680 | memcpy(dev->me_clients_map, enum_res->valid_addresses, 32); | 680 | BUILD_BUG_ON(sizeof(dev->me_clients_map) |
681 | < sizeof(enum_res->valid_addresses)); | ||
682 | memcpy(dev->me_clients_map, enum_res->valid_addresses, | ||
683 | sizeof(enum_res->valid_addresses)); | ||
681 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && | 684 | if (dev->dev_state == MEI_DEV_INIT_CLIENTS && |
682 | dev->hbm_state == MEI_HBM_ENUM_CLIENTS) { | 685 | dev->hbm_state == MEI_HBM_ENUM_CLIENTS) { |
683 | dev->init_clients_timer = 0; | 686 | dev->init_clients_timer = 0; |
diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h index 6a203b6e8346..6c0fde55270d 100644 --- a/drivers/misc/mei/hw-me-regs.h +++ b/drivers/misc/mei/hw-me-regs.h | |||
@@ -110,6 +110,7 @@ | |||
110 | #define MEI_DEV_ID_PPT_3 0x1DBA /* Panther Point */ | 110 | #define MEI_DEV_ID_PPT_3 0x1DBA /* Panther Point */ |
111 | 111 | ||
112 | #define MEI_DEV_ID_LPT 0x8C3A /* Lynx Point */ | 112 | #define MEI_DEV_ID_LPT 0x8C3A /* Lynx Point */ |
113 | #define MEI_DEV_ID_LPT_W 0x8D3A /* Lynx Point - Wellsburg */ | ||
113 | #define MEI_DEV_ID_LPT_LP 0x9C3A /* Lynx Point LP */ | 114 | #define MEI_DEV_ID_LPT_LP 0x9C3A /* Lynx Point LP */ |
114 | /* | 115 | /* |
115 | * MEI HW Section | 116 | * MEI HW Section |
diff --git a/drivers/misc/mei/init.c b/drivers/misc/mei/init.c index 6197018e2f16..f7f3abbe12b6 100644 --- a/drivers/misc/mei/init.c +++ b/drivers/misc/mei/init.c | |||
@@ -68,6 +68,14 @@ void mei_device_init(struct mei_device *dev) | |||
68 | mei_io_list_init(&dev->amthif_cmd_list); | 68 | mei_io_list_init(&dev->amthif_cmd_list); |
69 | mei_io_list_init(&dev->amthif_rd_complete_list); | 69 | mei_io_list_init(&dev->amthif_rd_complete_list); |
70 | 70 | ||
71 | bitmap_zero(dev->host_clients_map, MEI_CLIENTS_MAX); | ||
72 | dev->open_handle_count = 0; | ||
73 | |||
74 | /* | ||
75 | * Reserving the first client ID | ||
76 | * 0: Reserved for MEI Bus Message communications | ||
77 | */ | ||
78 | bitmap_set(dev->host_clients_map, 0, 1); | ||
71 | } | 79 | } |
72 | EXPORT_SYMBOL_GPL(mei_device_init); | 80 | EXPORT_SYMBOL_GPL(mei_device_init); |
73 | 81 | ||
@@ -139,6 +147,10 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) | |||
139 | dev->dev_state != MEI_DEV_POWER_DOWN && | 147 | dev->dev_state != MEI_DEV_POWER_DOWN && |
140 | dev->dev_state != MEI_DEV_POWER_UP); | 148 | dev->dev_state != MEI_DEV_POWER_UP); |
141 | 149 | ||
150 | if (unexpected) | ||
151 | dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", | ||
152 | mei_dev_state_str(dev->dev_state)); | ||
153 | |||
142 | ret = mei_hw_reset(dev, interrupts_enabled); | 154 | ret = mei_hw_reset(dev, interrupts_enabled); |
143 | if (ret) { | 155 | if (ret) { |
144 | dev_err(&dev->pdev->dev, "hw reset failed disabling the device\n"); | 156 | dev_err(&dev->pdev->dev, "hw reset failed disabling the device\n"); |
@@ -165,12 +177,7 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) | |||
165 | /* remove entry if already in list */ | 177 | /* remove entry if already in list */ |
166 | dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); | 178 | dev_dbg(&dev->pdev->dev, "remove iamthif and wd from the file list.\n"); |
167 | mei_cl_unlink(&dev->wd_cl); | 179 | mei_cl_unlink(&dev->wd_cl); |
168 | if (dev->open_handle_count > 0) | ||
169 | dev->open_handle_count--; | ||
170 | mei_cl_unlink(&dev->iamthif_cl); | 180 | mei_cl_unlink(&dev->iamthif_cl); |
171 | if (dev->open_handle_count > 0) | ||
172 | dev->open_handle_count--; | ||
173 | |||
174 | mei_amthif_reset_params(dev); | 181 | mei_amthif_reset_params(dev); |
175 | memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); | 182 | memset(&dev->wr_ext_msg, 0, sizeof(dev->wr_ext_msg)); |
176 | } | 183 | } |
@@ -182,10 +189,6 @@ void mei_reset(struct mei_device *dev, int interrupts_enabled) | |||
182 | dev->rd_msg_hdr = 0; | 189 | dev->rd_msg_hdr = 0; |
183 | dev->wd_pending = false; | 190 | dev->wd_pending = false; |
184 | 191 | ||
185 | if (unexpected) | ||
186 | dev_warn(&dev->pdev->dev, "unexpected reset: dev_state = %s\n", | ||
187 | mei_dev_state_str(dev->dev_state)); | ||
188 | |||
189 | if (!interrupts_enabled) { | 192 | if (!interrupts_enabled) { |
190 | dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n"); | 193 | dev_dbg(&dev->pdev->dev, "intr not enabled end of reset\n"); |
191 | return; | 194 | return; |
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 cabeddd66c1f..9661a812f550 100644 --- a/drivers/misc/mei/main.c +++ b/drivers/misc/mei/main.c | |||
@@ -60,48 +60,45 @@ static int mei_open(struct inode *inode, struct file *file) | |||
60 | 60 | ||
61 | int err; | 61 | int err; |
62 | 62 | ||
63 | err = -ENODEV; | ||
64 | if (!misc->parent) | 63 | if (!misc->parent) |
65 | goto out; | 64 | return -ENODEV; |
66 | 65 | ||
67 | pdev = container_of(misc->parent, struct pci_dev, dev); | 66 | pdev = container_of(misc->parent, struct pci_dev, dev); |
68 | 67 | ||
69 | dev = pci_get_drvdata(pdev); | 68 | dev = pci_get_drvdata(pdev); |
70 | if (!dev) | 69 | if (!dev) |
71 | goto out; | 70 | return -ENODEV; |
72 | 71 | ||
73 | mutex_lock(&dev->device_lock); | 72 | mutex_lock(&dev->device_lock); |
74 | err = -ENOMEM; | 73 | |
75 | cl = mei_cl_allocate(dev); | 74 | cl = NULL; |
76 | if (!cl) | ||
77 | goto out_unlock; | ||
78 | 75 | ||
79 | err = -ENODEV; | 76 | err = -ENODEV; |
80 | if (dev->dev_state != MEI_DEV_ENABLED) { | 77 | if (dev->dev_state != MEI_DEV_ENABLED) { |
81 | dev_dbg(&dev->pdev->dev, "dev_state != MEI_ENABLED dev_state = %s\n", | 78 | dev_dbg(&dev->pdev->dev, "dev_state != MEI_ENABLED dev_state = %s\n", |
82 | mei_dev_state_str(dev->dev_state)); | 79 | mei_dev_state_str(dev->dev_state)); |
83 | goto out_unlock; | 80 | goto err_unlock; |
84 | } | ||
85 | err = -EMFILE; | ||
86 | if (dev->open_handle_count >= MEI_MAX_OPEN_HANDLE_COUNT) { | ||
87 | dev_err(&dev->pdev->dev, "open_handle_count exceded %d", | ||
88 | MEI_MAX_OPEN_HANDLE_COUNT); | ||
89 | goto out_unlock; | ||
90 | } | 81 | } |
91 | 82 | ||
83 | err = -ENOMEM; | ||
84 | cl = mei_cl_allocate(dev); | ||
85 | if (!cl) | ||
86 | goto err_unlock; | ||
87 | |||
88 | /* open_handle_count check is handled in the mei_cl_link */ | ||
92 | err = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY); | 89 | err = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY); |
93 | if (err) | 90 | if (err) |
94 | goto out_unlock; | 91 | goto err_unlock; |
95 | 92 | ||
96 | file->private_data = cl; | 93 | file->private_data = cl; |
94 | |||
97 | mutex_unlock(&dev->device_lock); | 95 | mutex_unlock(&dev->device_lock); |
98 | 96 | ||
99 | return nonseekable_open(inode, file); | 97 | return nonseekable_open(inode, file); |
100 | 98 | ||
101 | out_unlock: | 99 | err_unlock: |
102 | mutex_unlock(&dev->device_lock); | 100 | mutex_unlock(&dev->device_lock); |
103 | kfree(cl); | 101 | kfree(cl); |
104 | out: | ||
105 | return err; | 102 | return err; |
106 | } | 103 | } |
107 | 104 | ||
@@ -144,10 +141,6 @@ static int mei_release(struct inode *inode, struct file *file) | |||
144 | cl->host_client_id, | 141 | cl->host_client_id, |
145 | cl->me_client_id); | 142 | cl->me_client_id); |
146 | 143 | ||
147 | if (dev->open_handle_count > 0) { | ||
148 | clear_bit(cl->host_client_id, dev->host_clients_map); | ||
149 | dev->open_handle_count--; | ||
150 | } | ||
151 | mei_cl_unlink(cl); | 144 | mei_cl_unlink(cl); |
152 | 145 | ||
153 | 146 | ||
@@ -165,10 +158,7 @@ static int mei_release(struct inode *inode, struct file *file) | |||
165 | 158 | ||
166 | file->private_data = NULL; | 159 | file->private_data = NULL; |
167 | 160 | ||
168 | if (cb) { | 161 | mei_io_cb_free(cb); |
169 | mei_io_cb_free(cb); | ||
170 | cb = NULL; | ||
171 | } | ||
172 | 162 | ||
173 | kfree(cl); | 163 | kfree(cl); |
174 | out: | 164 | out: |
@@ -203,12 +193,18 @@ static ssize_t mei_read(struct file *file, char __user *ubuf, | |||
203 | 193 | ||
204 | dev = cl->dev; | 194 | dev = cl->dev; |
205 | 195 | ||
196 | |||
206 | mutex_lock(&dev->device_lock); | 197 | mutex_lock(&dev->device_lock); |
207 | if (dev->dev_state != MEI_DEV_ENABLED) { | 198 | if (dev->dev_state != MEI_DEV_ENABLED) { |
208 | rets = -ENODEV; | 199 | rets = -ENODEV; |
209 | goto out; | 200 | goto out; |
210 | } | 201 | } |
211 | 202 | ||
203 | if (length == 0) { | ||
204 | rets = 0; | ||
205 | goto out; | ||
206 | } | ||
207 | |||
212 | if (cl == &dev->iamthif_cl) { | 208 | if (cl == &dev->iamthif_cl) { |
213 | rets = mei_amthif_read(dev, file, ubuf, length, offset); | 209 | rets = mei_amthif_read(dev, file, ubuf, length, offset); |
214 | goto out; | 210 | goto out; |
@@ -347,8 +343,14 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
347 | rets = -ENODEV; | 343 | rets = -ENODEV; |
348 | goto out; | 344 | goto out; |
349 | } | 345 | } |
350 | if (length > dev->me_clients[id].props.max_msg_length || length <= 0) { | 346 | |
351 | rets = -EMSGSIZE; | 347 | if (length == 0) { |
348 | rets = 0; | ||
349 | goto out; | ||
350 | } | ||
351 | |||
352 | if (length > dev->me_clients[id].props.max_msg_length) { | ||
353 | rets = -EFBIG; | ||
352 | goto out; | 354 | goto out; |
353 | } | 355 | } |
354 | 356 | ||
@@ -401,8 +403,11 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf, | |||
401 | goto out; | 403 | goto out; |
402 | 404 | ||
403 | rets = copy_from_user(write_cb->request_buffer.data, ubuf, length); | 405 | rets = copy_from_user(write_cb->request_buffer.data, ubuf, length); |
404 | if (rets) | 406 | if (rets) { |
407 | dev_err(&dev->pdev->dev, "failed to copy data from userland\n"); | ||
408 | rets = -EFAULT; | ||
405 | goto out; | 409 | goto out; |
410 | } | ||
406 | 411 | ||
407 | if (cl == &dev->iamthif_cl) { | 412 | if (cl == &dev->iamthif_cl) { |
408 | rets = mei_amthif_write(dev, write_cb); | 413 | rets = mei_amthif_write(dev, write_cb); |
@@ -489,11 +494,11 @@ static int mei_ioctl_connect_client(struct file *file, | |||
489 | rets = -ENODEV; | 494 | rets = -ENODEV; |
490 | goto end; | 495 | goto end; |
491 | } | 496 | } |
492 | clear_bit(cl->host_client_id, dev->host_clients_map); | ||
493 | mei_cl_unlink(cl); | 497 | mei_cl_unlink(cl); |
494 | 498 | ||
495 | kfree(cl); | 499 | kfree(cl); |
496 | cl = NULL; | 500 | cl = NULL; |
501 | dev->iamthif_open_count++; | ||
497 | file->private_data = &dev->iamthif_cl; | 502 | file->private_data = &dev->iamthif_cl; |
498 | 503 | ||
499 | client = &data->out_client_properties; | 504 | client = &data->out_client_properties; |
@@ -564,7 +569,7 @@ static long mei_ioctl(struct file *file, unsigned int cmd, unsigned long data) | |||
564 | dev_dbg(&dev->pdev->dev, "copy connect data from user\n"); | 569 | dev_dbg(&dev->pdev->dev, "copy connect data from user\n"); |
565 | if (copy_from_user(connect_data, (char __user *)data, | 570 | if (copy_from_user(connect_data, (char __user *)data, |
566 | sizeof(struct mei_connect_client_data))) { | 571 | sizeof(struct mei_connect_client_data))) { |
567 | dev_dbg(&dev->pdev->dev, "failed to copy data from userland\n"); | 572 | dev_err(&dev->pdev->dev, "failed to copy data from userland\n"); |
568 | rets = -EFAULT; | 573 | rets = -EFAULT; |
569 | goto out; | 574 | goto out; |
570 | } | 575 | } |
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h index 456b322013e2..406f68e05b4e 100644 --- a/drivers/misc/mei/mei_dev.h +++ b/drivers/misc/mei/mei_dev.h | |||
@@ -414,6 +414,7 @@ struct mei_device { | |||
414 | struct file *iamthif_file_object; | 414 | struct file *iamthif_file_object; |
415 | struct mei_cl iamthif_cl; | 415 | struct mei_cl iamthif_cl; |
416 | struct mei_cl_cb *iamthif_current_cb; | 416 | struct mei_cl_cb *iamthif_current_cb; |
417 | long iamthif_open_count; | ||
417 | int iamthif_mtu; | 418 | int iamthif_mtu; |
418 | unsigned long iamthif_timer; | 419 | unsigned long iamthif_timer; |
419 | u32 iamthif_stall_timer; | 420 | u32 iamthif_stall_timer; |
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c index d0c6907dfd92..994ca4aff1a3 100644 --- a/drivers/misc/mei/nfc.c +++ b/drivers/misc/mei/nfc.c | |||
@@ -485,8 +485,11 @@ int mei_nfc_host_init(struct mei_device *dev) | |||
485 | if (ndev->cl_info) | 485 | if (ndev->cl_info) |
486 | return 0; | 486 | return 0; |
487 | 487 | ||
488 | cl_info = mei_cl_allocate(dev); | 488 | ndev->cl_info = mei_cl_allocate(dev); |
489 | cl = mei_cl_allocate(dev); | 489 | ndev->cl = mei_cl_allocate(dev); |
490 | |||
491 | cl = ndev->cl; | ||
492 | cl_info = ndev->cl_info; | ||
490 | 493 | ||
491 | if (!cl || !cl_info) { | 494 | if (!cl || !cl_info) { |
492 | ret = -ENOMEM; | 495 | ret = -ENOMEM; |
@@ -527,10 +530,9 @@ int mei_nfc_host_init(struct mei_device *dev) | |||
527 | 530 | ||
528 | cl->device_uuid = mei_nfc_guid; | 531 | cl->device_uuid = mei_nfc_guid; |
529 | 532 | ||
533 | |||
530 | list_add_tail(&cl->device_link, &dev->device_list); | 534 | list_add_tail(&cl->device_link, &dev->device_list); |
531 | 535 | ||
532 | ndev->cl_info = cl_info; | ||
533 | ndev->cl = cl; | ||
534 | ndev->req_id = 1; | 536 | ndev->req_id = 1; |
535 | 537 | ||
536 | INIT_WORK(&ndev->init_work, mei_nfc_init); | 538 | INIT_WORK(&ndev->init_work, mei_nfc_init); |
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c index 1b3844e82379..b96205aece0c 100644 --- a/drivers/misc/mei/pci-me.c +++ b/drivers/misc/mei/pci-me.c | |||
@@ -77,6 +77,7 @@ static DEFINE_PCI_DEVICE_TABLE(mei_me_pci_tbl) = { | |||
77 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)}, | 77 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_2)}, |
78 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)}, | 78 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_PPT_3)}, |
79 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT)}, | 79 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT)}, |
80 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_W)}, | ||
80 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)}, | 81 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MEI_DEV_ID_LPT_LP)}, |
81 | 82 | ||
82 | /* required last entry */ | 83 | /* required last entry */ |
@@ -189,7 +190,7 @@ static int mei_me_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
189 | 190 | ||
190 | schedule_delayed_work(&dev->timer_work, HZ); | 191 | schedule_delayed_work(&dev->timer_work, HZ); |
191 | 192 | ||
192 | pr_debug("initialization successful.\n"); | 193 | dev_dbg(&pdev->dev, "initialization successful.\n"); |
193 | 194 | ||
194 | return 0; | 195 | return 0; |
195 | 196 | ||
@@ -231,7 +232,7 @@ static void mei_me_remove(struct pci_dev *pdev) | |||
231 | hw = to_me_hw(dev); | 232 | hw = to_me_hw(dev); |
232 | 233 | ||
233 | 234 | ||
234 | dev_err(&pdev->dev, "stop\n"); | 235 | dev_dbg(&pdev->dev, "stop\n"); |
235 | mei_stop(dev); | 236 | mei_stop(dev); |
236 | 237 | ||
237 | /* disable interrupts */ | 238 | /* disable interrupts */ |
@@ -239,7 +240,6 @@ static void mei_me_remove(struct pci_dev *pdev) | |||
239 | 240 | ||
240 | free_irq(pdev->irq, dev); | 241 | free_irq(pdev->irq, dev); |
241 | pci_disable_msi(pdev); | 242 | pci_disable_msi(pdev); |
242 | pci_set_drvdata(pdev, NULL); | ||
243 | 243 | ||
244 | if (hw->mem_addr) | 244 | if (hw->mem_addr) |
245 | pci_iounmap(pdev, hw->mem_addr); | 245 | pci_iounmap(pdev, hw->mem_addr); |
@@ -262,7 +262,7 @@ static int mei_me_pci_suspend(struct device *device) | |||
262 | if (!dev) | 262 | if (!dev) |
263 | return -ENODEV; | 263 | return -ENODEV; |
264 | 264 | ||
265 | dev_err(&pdev->dev, "suspend\n"); | 265 | dev_dbg(&pdev->dev, "suspend\n"); |
266 | 266 | ||
267 | mei_stop(dev); | 267 | mei_stop(dev); |
268 | 268 | ||
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index b8921432e89d..9e354216c163 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c | |||
@@ -60,7 +60,7 @@ static void mei_wd_set_start_timeout(struct mei_device *dev, u16 timeout) | |||
60 | int mei_wd_host_init(struct mei_device *dev) | 60 | int mei_wd_host_init(struct mei_device *dev) |
61 | { | 61 | { |
62 | struct mei_cl *cl = &dev->wd_cl; | 62 | struct mei_cl *cl = &dev->wd_cl; |
63 | int i; | 63 | int id; |
64 | int ret; | 64 | int ret; |
65 | 65 | ||
66 | mei_cl_init(cl, dev); | 66 | mei_cl_init(cl, dev); |
@@ -70,19 +70,19 @@ int mei_wd_host_init(struct mei_device *dev) | |||
70 | 70 | ||
71 | 71 | ||
72 | /* check for valid client id */ | 72 | /* check for valid client id */ |
73 | i = mei_me_cl_by_uuid(dev, &mei_wd_guid); | 73 | id = mei_me_cl_by_uuid(dev, &mei_wd_guid); |
74 | if (i < 0) { | 74 | if (id < 0) { |
75 | dev_info(&dev->pdev->dev, "wd: failed to find the client\n"); | 75 | dev_info(&dev->pdev->dev, "wd: failed to find the client\n"); |
76 | return -ENOENT; | 76 | return id; |
77 | } | 77 | } |
78 | 78 | ||
79 | cl->me_client_id = dev->me_clients[i].client_id; | 79 | cl->me_client_id = dev->me_clients[id].client_id; |
80 | 80 | ||
81 | ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID); | 81 | ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID); |
82 | 82 | ||
83 | if (ret < 0) { | 83 | if (ret < 0) { |
84 | dev_info(&dev->pdev->dev, "wd: failed link client\n"); | 84 | dev_info(&dev->pdev->dev, "wd: failed link client\n"); |
85 | return -ENOENT; | 85 | return ret; |
86 | } | 86 | } |
87 | 87 | ||
88 | cl->state = MEI_FILE_CONNECTING; | 88 | cl->state = MEI_FILE_CONNECTING; |
diff --git a/drivers/misc/mic/Kconfig b/drivers/misc/mic/Kconfig new file mode 100644 index 000000000000..e42b331edbc6 --- /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 && X86 | ||
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 && X86 | ||
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..421b3d7911df --- /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_dev.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..d0980ff96833 --- /dev/null +++ b/drivers/misc/mic/card/mic_device.c | |||
@@ -0,0 +1,305 @@ | |||
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_dev.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 | * mic_free_card_irq - free irq. | ||
174 | * | ||
175 | * @cookie: cookie obtained during a successful call to mic_request_irq | ||
176 | * @data: private data specified by the calling function during the | ||
177 | * mic_request_irq | ||
178 | * | ||
179 | * returns: none. | ||
180 | */ | ||
181 | void mic_free_card_irq(struct mic_irq *cookie, void *data) | ||
182 | { | ||
183 | int index; | ||
184 | struct mic_driver *mdrv = g_drv; | ||
185 | |||
186 | index = (unsigned long)cookie & 0xFFFFU; | ||
187 | free_irq(mic_db_to_irq(mdrv, index), data); | ||
188 | mdrv->irq_info.irq_usage_count[index]--; | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * mic_next_card_db - Get the doorbell with minimum usage count. | ||
193 | * | ||
194 | * Returns the irq index. | ||
195 | */ | ||
196 | int mic_next_card_db(void) | ||
197 | { | ||
198 | int i; | ||
199 | int index = 0; | ||
200 | struct mic_driver *mdrv = g_drv; | ||
201 | |||
202 | for (i = 0; i < mdrv->intr_info.num_intr; i++) { | ||
203 | if (mdrv->irq_info.irq_usage_count[i] < | ||
204 | mdrv->irq_info.irq_usage_count[index]) | ||
205 | index = i; | ||
206 | } | ||
207 | |||
208 | return index; | ||
209 | } | ||
210 | |||
211 | /** | ||
212 | * mic_init_irq - Initialize irq information. | ||
213 | * | ||
214 | * Returns 0 in success. Appropriate error code on failure. | ||
215 | */ | ||
216 | static int mic_init_irq(void) | ||
217 | { | ||
218 | struct mic_driver *mdrv = g_drv; | ||
219 | |||
220 | mdrv->irq_info.irq_usage_count = kzalloc((sizeof(u32) * | ||
221 | mdrv->intr_info.num_intr), | ||
222 | GFP_KERNEL); | ||
223 | if (!mdrv->irq_info.irq_usage_count) | ||
224 | return -ENOMEM; | ||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | /** | ||
229 | * mic_uninit_irq - Uninitialize irq information. | ||
230 | * | ||
231 | * None. | ||
232 | */ | ||
233 | static void mic_uninit_irq(void) | ||
234 | { | ||
235 | struct mic_driver *mdrv = g_drv; | ||
236 | |||
237 | kfree(mdrv->irq_info.irq_usage_count); | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * mic_driver_init - MIC driver initialization tasks. | ||
242 | * | ||
243 | * Returns 0 in success. Appropriate error code on failure. | ||
244 | */ | ||
245 | int __init mic_driver_init(struct mic_driver *mdrv) | ||
246 | { | ||
247 | int rc; | ||
248 | |||
249 | g_drv = mdrv; | ||
250 | /* | ||
251 | * Unloading the card module is not supported. The MIC card module | ||
252 | * handles fundamental operations like host/card initiated shutdowns | ||
253 | * and informing the host about card crashes and cannot be unloaded. | ||
254 | */ | ||
255 | if (!try_module_get(mdrv->dev->driver->owner)) { | ||
256 | rc = -ENODEV; | ||
257 | goto done; | ||
258 | } | ||
259 | rc = mic_dp_init(); | ||
260 | if (rc) | ||
261 | goto put; | ||
262 | rc = mic_init_irq(); | ||
263 | if (rc) | ||
264 | goto dp_uninit; | ||
265 | rc = mic_shutdown_init(); | ||
266 | if (rc) | ||
267 | goto irq_uninit; | ||
268 | rc = mic_devices_init(mdrv); | ||
269 | if (rc) | ||
270 | goto shutdown_uninit; | ||
271 | mic_create_card_debug_dir(mdrv); | ||
272 | atomic_notifier_chain_register(&panic_notifier_list, &mic_panic); | ||
273 | done: | ||
274 | return rc; | ||
275 | shutdown_uninit: | ||
276 | mic_shutdown_uninit(); | ||
277 | irq_uninit: | ||
278 | mic_uninit_irq(); | ||
279 | dp_uninit: | ||
280 | mic_dp_uninit(); | ||
281 | put: | ||
282 | module_put(mdrv->dev->driver->owner); | ||
283 | return rc; | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * mic_driver_uninit - MIC driver uninitialization tasks. | ||
288 | * | ||
289 | * Returns None | ||
290 | */ | ||
291 | void mic_driver_uninit(struct mic_driver *mdrv) | ||
292 | { | ||
293 | mic_delete_card_debug_dir(mdrv); | ||
294 | mic_devices_uninit(mdrv); | ||
295 | /* | ||
296 | * Inform the host about the shutdown status i.e. poweroff/restart etc. | ||
297 | * The module cannot be unloaded so the only code path to call | ||
298 | * mic_devices_uninit(..) is the shutdown callback. | ||
299 | */ | ||
300 | mic_notify_host(system_state); | ||
301 | mic_shutdown_uninit(); | ||
302 | mic_uninit_irq(); | ||
303 | mic_dp_uninit(); | ||
304 | module_put(mdrv->dev->driver->owner); | ||
305 | } | ||
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..914cc9b2caad --- /dev/null +++ b/drivers/misc/mic/card/mic_virtio.c | |||
@@ -0,0 +1,630 @@ | |||
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_dev.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, get_order(mvdev->used_size[n])); | ||
203 | vring_del_virtqueue(vq); | ||
204 | mic_card_unmap(mvdev->mdev, mvdev->vr[n]); | ||
205 | mvdev->vr[n] = NULL; | ||
206 | } | ||
207 | |||
208 | static void mic_del_vqs(struct virtio_device *vdev) | ||
209 | { | ||
210 | struct mic_vdev *mvdev = to_micvdev(vdev); | ||
211 | struct virtqueue *vq, *n; | ||
212 | int idx = 0; | ||
213 | |||
214 | dev_dbg(mic_dev(mvdev), "%s\n", __func__); | ||
215 | |||
216 | list_for_each_entry_safe(vq, n, &vdev->vqs, list) | ||
217 | mic_del_vq(vq, idx++); | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * This routine will assign vring's allocated in host/io memory. Code in | ||
222 | * virtio_ring.c however continues to access this io memory as if it were local | ||
223 | * memory without io accessors. | ||
224 | */ | ||
225 | static struct virtqueue *mic_find_vq(struct virtio_device *vdev, | ||
226 | unsigned index, | ||
227 | void (*callback)(struct virtqueue *vq), | ||
228 | const char *name) | ||
229 | { | ||
230 | struct mic_vdev *mvdev = to_micvdev(vdev); | ||
231 | struct mic_vqconfig __iomem *vqconfig; | ||
232 | struct mic_vqconfig config; | ||
233 | struct virtqueue *vq; | ||
234 | void __iomem *va; | ||
235 | struct _mic_vring_info __iomem *info; | ||
236 | void *used; | ||
237 | int vr_size, _vr_size, err, magic; | ||
238 | struct vring *vr; | ||
239 | u8 type = ioread8(&mvdev->desc->type); | ||
240 | |||
241 | if (index >= ioread8(&mvdev->desc->num_vq)) | ||
242 | return ERR_PTR(-ENOENT); | ||
243 | |||
244 | if (!name) | ||
245 | return ERR_PTR(-ENOENT); | ||
246 | |||
247 | /* First assign the vring's allocated in host memory */ | ||
248 | vqconfig = mic_vq_config(mvdev->desc) + index; | ||
249 | memcpy_fromio(&config, vqconfig, sizeof(config)); | ||
250 | _vr_size = vring_size(config.num, MIC_VIRTIO_RING_ALIGN); | ||
251 | vr_size = PAGE_ALIGN(_vr_size + sizeof(struct _mic_vring_info)); | ||
252 | va = mic_card_map(mvdev->mdev, config.address, vr_size); | ||
253 | if (!va) | ||
254 | return ERR_PTR(-ENOMEM); | ||
255 | mvdev->vr[index] = va; | ||
256 | memset_io(va, 0x0, _vr_size); | ||
257 | vq = vring_new_virtqueue(index, | ||
258 | config.num, MIC_VIRTIO_RING_ALIGN, vdev, | ||
259 | false, | ||
260 | va, mic_notify, callback, name); | ||
261 | if (!vq) { | ||
262 | err = -ENOMEM; | ||
263 | goto unmap; | ||
264 | } | ||
265 | info = va + _vr_size; | ||
266 | magic = ioread32(&info->magic); | ||
267 | |||
268 | if (WARN(magic != MIC_MAGIC + type + index, "magic mismatch")) { | ||
269 | err = -EIO; | ||
270 | goto unmap; | ||
271 | } | ||
272 | |||
273 | /* Allocate and reassign used ring now */ | ||
274 | mvdev->used_size[index] = PAGE_ALIGN(sizeof(__u16) * 3 + | ||
275 | sizeof(struct vring_used_elem) * config.num); | ||
276 | used = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, | ||
277 | get_order(mvdev->used_size[index])); | ||
278 | if (!used) { | ||
279 | err = -ENOMEM; | ||
280 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
281 | __func__, __LINE__, err); | ||
282 | goto del_vq; | ||
283 | } | ||
284 | iowrite64(virt_to_phys(used), &vqconfig->used_address); | ||
285 | |||
286 | /* | ||
287 | * To reassign the used ring here we are directly accessing | ||
288 | * struct vring_virtqueue which is a private data structure | ||
289 | * in virtio_ring.c. At the minimum, a BUILD_BUG_ON() in | ||
290 | * vring_new_virtqueue() would ensure that | ||
291 | * (&vq->vring == (struct vring *) (&vq->vq + 1)); | ||
292 | */ | ||
293 | vr = (struct vring *)(vq + 1); | ||
294 | vr->used = used; | ||
295 | |||
296 | vq->priv = mvdev; | ||
297 | return vq; | ||
298 | del_vq: | ||
299 | vring_del_virtqueue(vq); | ||
300 | unmap: | ||
301 | mic_card_unmap(mvdev->mdev, mvdev->vr[index]); | ||
302 | return ERR_PTR(err); | ||
303 | } | ||
304 | |||
305 | static int mic_find_vqs(struct virtio_device *vdev, unsigned nvqs, | ||
306 | struct virtqueue *vqs[], | ||
307 | vq_callback_t *callbacks[], | ||
308 | const char *names[]) | ||
309 | { | ||
310 | struct mic_vdev *mvdev = to_micvdev(vdev); | ||
311 | struct mic_device_ctrl __iomem *dc = mvdev->dc; | ||
312 | int i, err, retry = 100; | ||
313 | |||
314 | /* We must have this many virtqueues. */ | ||
315 | if (nvqs > ioread8(&mvdev->desc->num_vq)) | ||
316 | return -ENOENT; | ||
317 | |||
318 | for (i = 0; i < nvqs; ++i) { | ||
319 | dev_dbg(mic_dev(mvdev), "%s: %d: %s\n", | ||
320 | __func__, i, names[i]); | ||
321 | vqs[i] = mic_find_vq(vdev, i, callbacks[i], names[i]); | ||
322 | if (IS_ERR(vqs[i])) { | ||
323 | err = PTR_ERR(vqs[i]); | ||
324 | goto error; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | iowrite8(1, &dc->used_address_updated); | ||
329 | /* | ||
330 | * Send an interrupt to the host to inform it that used | ||
331 | * rings have been re-assigned. | ||
332 | */ | ||
333 | mic_send_intr(mvdev->mdev, mvdev->c2h_vdev_db); | ||
334 | for (i = retry; i--;) { | ||
335 | if (!ioread8(&dc->used_address_updated)) | ||
336 | break; | ||
337 | msleep(100); | ||
338 | }; | ||
339 | |||
340 | dev_dbg(mic_dev(mvdev), "%s: retry: %d\n", __func__, retry); | ||
341 | if (!retry) { | ||
342 | err = -ENODEV; | ||
343 | goto error; | ||
344 | } | ||
345 | |||
346 | return 0; | ||
347 | error: | ||
348 | mic_del_vqs(vdev); | ||
349 | return err; | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * The config ops structure as defined by virtio config | ||
354 | */ | ||
355 | static struct virtio_config_ops mic_vq_config_ops = { | ||
356 | .get_features = mic_get_features, | ||
357 | .finalize_features = mic_finalize_features, | ||
358 | .get = mic_get, | ||
359 | .set = mic_set, | ||
360 | .get_status = mic_get_status, | ||
361 | .set_status = mic_set_status, | ||
362 | .reset = mic_reset, | ||
363 | .find_vqs = mic_find_vqs, | ||
364 | .del_vqs = mic_del_vqs, | ||
365 | }; | ||
366 | |||
367 | static irqreturn_t | ||
368 | mic_virtio_intr_handler(int irq, void *data) | ||
369 | { | ||
370 | struct mic_vdev *mvdev = data; | ||
371 | struct virtqueue *vq; | ||
372 | |||
373 | mic_ack_interrupt(mvdev->mdev); | ||
374 | list_for_each_entry(vq, &mvdev->vdev.vqs, list) | ||
375 | vring_interrupt(0, vq); | ||
376 | |||
377 | return IRQ_HANDLED; | ||
378 | } | ||
379 | |||
380 | static void mic_virtio_release_dev(struct device *_d) | ||
381 | { | ||
382 | /* | ||
383 | * No need for a release method similar to virtio PCI. | ||
384 | * Provide an empty one to avoid getting a warning from core. | ||
385 | */ | ||
386 | } | ||
387 | |||
388 | /* | ||
389 | * adds a new device and register it with virtio | ||
390 | * appropriate drivers are loaded by the device model | ||
391 | */ | ||
392 | static int mic_add_device(struct mic_device_desc __iomem *d, | ||
393 | unsigned int offset, struct mic_driver *mdrv) | ||
394 | { | ||
395 | struct mic_vdev *mvdev; | ||
396 | int ret; | ||
397 | int virtio_db; | ||
398 | u8 type = ioread8(&d->type); | ||
399 | |||
400 | mvdev = kzalloc(sizeof(*mvdev), GFP_KERNEL); | ||
401 | if (!mvdev) { | ||
402 | dev_err(mdrv->dev, "Cannot allocate mic dev %u type %u\n", | ||
403 | offset, type); | ||
404 | return -ENOMEM; | ||
405 | } | ||
406 | |||
407 | mvdev->mdev = &mdrv->mdev; | ||
408 | mvdev->vdev.dev.parent = mdrv->dev; | ||
409 | mvdev->vdev.dev.release = mic_virtio_release_dev; | ||
410 | mvdev->vdev.id.device = type; | ||
411 | mvdev->vdev.config = &mic_vq_config_ops; | ||
412 | mvdev->desc = d; | ||
413 | mvdev->dc = (void __iomem *)d + mic_aligned_desc_size(d); | ||
414 | init_completion(&mvdev->reset_done); | ||
415 | |||
416 | virtio_db = mic_next_card_db(); | ||
417 | mvdev->virtio_cookie = mic_request_card_irq(mic_virtio_intr_handler, | ||
418 | "virtio intr", mvdev, virtio_db); | ||
419 | if (IS_ERR(mvdev->virtio_cookie)) { | ||
420 | ret = PTR_ERR(mvdev->virtio_cookie); | ||
421 | goto kfree; | ||
422 | } | ||
423 | iowrite8((u8)virtio_db, &mvdev->dc->h2c_vdev_db); | ||
424 | mvdev->c2h_vdev_db = ioread8(&mvdev->dc->c2h_vdev_db); | ||
425 | |||
426 | ret = register_virtio_device(&mvdev->vdev); | ||
427 | if (ret) { | ||
428 | dev_err(mic_dev(mvdev), | ||
429 | "Failed to register mic device %u type %u\n", | ||
430 | offset, type); | ||
431 | goto free_irq; | ||
432 | } | ||
433 | iowrite64((u64)mvdev, &mvdev->dc->vdev); | ||
434 | dev_dbg(mic_dev(mvdev), "%s: registered mic device %u type %u mvdev %p\n", | ||
435 | __func__, offset, type, mvdev); | ||
436 | |||
437 | return 0; | ||
438 | |||
439 | free_irq: | ||
440 | mic_free_card_irq(mvdev->virtio_cookie, mvdev); | ||
441 | kfree: | ||
442 | kfree(mvdev); | ||
443 | return ret; | ||
444 | } | ||
445 | |||
446 | /* | ||
447 | * match for a mic device with a specific desc pointer | ||
448 | */ | ||
449 | static int mic_match_desc(struct device *dev, void *data) | ||
450 | { | ||
451 | struct virtio_device *vdev = dev_to_virtio(dev); | ||
452 | struct mic_vdev *mvdev = to_micvdev(vdev); | ||
453 | |||
454 | return mvdev->desc == (void __iomem *)data; | ||
455 | } | ||
456 | |||
457 | static void mic_handle_config_change(struct mic_device_desc __iomem *d, | ||
458 | unsigned int offset, struct mic_driver *mdrv) | ||
459 | { | ||
460 | struct mic_device_ctrl __iomem *dc | ||
461 | = (void __iomem *)d + mic_aligned_desc_size(d); | ||
462 | struct mic_vdev *mvdev = (struct mic_vdev *)ioread64(&dc->vdev); | ||
463 | struct virtio_driver *drv; | ||
464 | |||
465 | if (ioread8(&dc->config_change) != MIC_VIRTIO_PARAM_CONFIG_CHANGED) | ||
466 | return; | ||
467 | |||
468 | dev_dbg(mdrv->dev, "%s %d\n", __func__, __LINE__); | ||
469 | drv = container_of(mvdev->vdev.dev.driver, | ||
470 | struct virtio_driver, driver); | ||
471 | if (drv->config_changed) | ||
472 | drv->config_changed(&mvdev->vdev); | ||
473 | iowrite8(1, &dc->guest_ack); | ||
474 | } | ||
475 | |||
476 | /* | ||
477 | * removes a virtio device if a hot remove event has been | ||
478 | * requested by the host. | ||
479 | */ | ||
480 | static int mic_remove_device(struct mic_device_desc __iomem *d, | ||
481 | unsigned int offset, struct mic_driver *mdrv) | ||
482 | { | ||
483 | struct mic_device_ctrl __iomem *dc | ||
484 | = (void __iomem *)d + mic_aligned_desc_size(d); | ||
485 | struct mic_vdev *mvdev = (struct mic_vdev *)ioread64(&dc->vdev); | ||
486 | u8 status; | ||
487 | int ret = -1; | ||
488 | |||
489 | if (ioread8(&dc->config_change) == MIC_VIRTIO_PARAM_DEV_REMOVE) { | ||
490 | dev_dbg(mdrv->dev, | ||
491 | "%s %d config_change %d type %d mvdev %p\n", | ||
492 | __func__, __LINE__, | ||
493 | ioread8(&dc->config_change), ioread8(&d->type), mvdev); | ||
494 | |||
495 | status = ioread8(&d->status); | ||
496 | INIT_COMPLETION(mvdev->reset_done); | ||
497 | unregister_virtio_device(&mvdev->vdev); | ||
498 | mic_free_card_irq(mvdev->virtio_cookie, mvdev); | ||
499 | if (status & VIRTIO_CONFIG_S_DRIVER_OK) | ||
500 | wait_for_completion(&mvdev->reset_done); | ||
501 | kfree(mvdev); | ||
502 | iowrite8(1, &dc->guest_ack); | ||
503 | dev_dbg(mdrv->dev, "%s %d guest_ack %d\n", | ||
504 | __func__, __LINE__, ioread8(&dc->guest_ack)); | ||
505 | ret = 0; | ||
506 | } | ||
507 | |||
508 | return ret; | ||
509 | } | ||
510 | |||
511 | #define REMOVE_DEVICES true | ||
512 | |||
513 | static void mic_scan_devices(struct mic_driver *mdrv, bool remove) | ||
514 | { | ||
515 | s8 type; | ||
516 | unsigned int i; | ||
517 | struct mic_device_desc __iomem *d; | ||
518 | struct mic_device_ctrl __iomem *dc; | ||
519 | struct device *dev; | ||
520 | int ret; | ||
521 | |||
522 | for (i = mic_aligned_size(struct mic_bootparam); | ||
523 | i < MIC_DP_SIZE; i += mic_total_desc_size(d)) { | ||
524 | d = mdrv->dp + i; | ||
525 | dc = (void __iomem *)d + mic_aligned_desc_size(d); | ||
526 | /* | ||
527 | * This read barrier is paired with the corresponding write | ||
528 | * barrier on the host which is inserted before adding or | ||
529 | * removing a virtio device descriptor, by updating the type. | ||
530 | */ | ||
531 | rmb(); | ||
532 | type = ioread8(&d->type); | ||
533 | |||
534 | /* end of list */ | ||
535 | if (type == 0) | ||
536 | break; | ||
537 | |||
538 | if (type == -1) | ||
539 | continue; | ||
540 | |||
541 | /* device already exists */ | ||
542 | dev = device_find_child(mdrv->dev, d, mic_match_desc); | ||
543 | if (dev) { | ||
544 | if (remove) | ||
545 | iowrite8(MIC_VIRTIO_PARAM_DEV_REMOVE, | ||
546 | &dc->config_change); | ||
547 | put_device(dev); | ||
548 | mic_handle_config_change(d, i, mdrv); | ||
549 | ret = mic_remove_device(d, i, mdrv); | ||
550 | if (!ret && !remove) | ||
551 | iowrite8(-1, &d->type); | ||
552 | if (remove) { | ||
553 | iowrite8(0, &dc->config_change); | ||
554 | iowrite8(0, &dc->guest_ack); | ||
555 | } | ||
556 | continue; | ||
557 | } | ||
558 | |||
559 | /* new device */ | ||
560 | dev_dbg(mdrv->dev, "%s %d Adding new virtio device %p\n", | ||
561 | __func__, __LINE__, d); | ||
562 | if (!remove) | ||
563 | mic_add_device(d, i, mdrv); | ||
564 | } | ||
565 | } | ||
566 | |||
567 | /* | ||
568 | * mic_hotplug_device tries to find changes in the device page. | ||
569 | */ | ||
570 | static void mic_hotplug_devices(struct work_struct *work) | ||
571 | { | ||
572 | struct mic_driver *mdrv = container_of(work, | ||
573 | struct mic_driver, hotplug_work); | ||
574 | |||
575 | mic_scan_devices(mdrv, !REMOVE_DEVICES); | ||
576 | } | ||
577 | |||
578 | /* | ||
579 | * Interrupt handler for hot plug/config changes etc. | ||
580 | */ | ||
581 | static irqreturn_t | ||
582 | mic_extint_handler(int irq, void *data) | ||
583 | { | ||
584 | struct mic_driver *mdrv = (struct mic_driver *)data; | ||
585 | |||
586 | dev_dbg(mdrv->dev, "%s %d hotplug work\n", | ||
587 | __func__, __LINE__); | ||
588 | mic_ack_interrupt(&mdrv->mdev); | ||
589 | schedule_work(&mdrv->hotplug_work); | ||
590 | return IRQ_HANDLED; | ||
591 | } | ||
592 | |||
593 | /* | ||
594 | * Init function for virtio | ||
595 | */ | ||
596 | int mic_devices_init(struct mic_driver *mdrv) | ||
597 | { | ||
598 | int rc; | ||
599 | struct mic_bootparam __iomem *bootparam; | ||
600 | int config_db; | ||
601 | |||
602 | INIT_WORK(&mdrv->hotplug_work, mic_hotplug_devices); | ||
603 | mic_scan_devices(mdrv, !REMOVE_DEVICES); | ||
604 | |||
605 | config_db = mic_next_card_db(); | ||
606 | virtio_config_cookie = mic_request_card_irq(mic_extint_handler, | ||
607 | "virtio_config_intr", mdrv, config_db); | ||
608 | if (IS_ERR(virtio_config_cookie)) { | ||
609 | rc = PTR_ERR(virtio_config_cookie); | ||
610 | goto exit; | ||
611 | } | ||
612 | |||
613 | bootparam = mdrv->dp; | ||
614 | iowrite8(config_db, &bootparam->h2c_config_db); | ||
615 | return 0; | ||
616 | exit: | ||
617 | return rc; | ||
618 | } | ||
619 | |||
620 | /* | ||
621 | * Uninit function for virtio | ||
622 | */ | ||
623 | void mic_devices_uninit(struct mic_driver *mdrv) | ||
624 | { | ||
625 | struct mic_bootparam __iomem *bootparam = mdrv->dp; | ||
626 | iowrite8(-1, &bootparam->h2c_config_db); | ||
627 | mic_free_card_irq(virtio_config_cookie, mdrv); | ||
628 | flush_work(&mdrv->hotplug_work); | ||
629 | mic_scan_devices(mdrv, REMOVE_DEVICES); | ||
630 | } | ||
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..2868945c9a4d --- /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_dev.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_dev.h b/drivers/misc/mic/common/mic_dev.h new file mode 100644 index 000000000000..92999c2bbf82 --- /dev/null +++ b/drivers/misc/mic/common/mic_dev.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_DEV_H__ | ||
22 | #define __MIC_DEV_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..b079c65eed6d --- /dev/null +++ b/drivers/misc/mic/host/mic_boot.c | |||
@@ -0,0 +1,300 @@ | |||
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 | #include <linux/pci.h> | ||
24 | |||
25 | #include <linux/mic_common.h> | ||
26 | #include "../common/mic_dev.h" | ||
27 | #include "mic_device.h" | ||
28 | #include "mic_smpt.h" | ||
29 | #include "mic_virtio.h" | ||
30 | |||
31 | /** | ||
32 | * mic_reset - Reset the MIC device. | ||
33 | * @mdev: pointer to mic_device instance | ||
34 | */ | ||
35 | static void mic_reset(struct mic_device *mdev) | ||
36 | { | ||
37 | int i; | ||
38 | |||
39 | #define MIC_RESET_TO (45) | ||
40 | |||
41 | INIT_COMPLETION(mdev->reset_wait); | ||
42 | mdev->ops->reset_fw_ready(mdev); | ||
43 | mdev->ops->reset(mdev); | ||
44 | |||
45 | for (i = 0; i < MIC_RESET_TO; i++) { | ||
46 | if (mdev->ops->is_fw_ready(mdev)) | ||
47 | goto done; | ||
48 | /* | ||
49 | * Resets typically take 10s of seconds to complete. | ||
50 | * Since an MMIO read is required to check if the | ||
51 | * firmware is ready or not, a 1 second delay works nicely. | ||
52 | */ | ||
53 | msleep(1000); | ||
54 | } | ||
55 | mic_set_state(mdev, MIC_RESET_FAILED); | ||
56 | done: | ||
57 | complete_all(&mdev->reset_wait); | ||
58 | } | ||
59 | |||
60 | /* Initialize the MIC bootparams */ | ||
61 | void mic_bootparam_init(struct mic_device *mdev) | ||
62 | { | ||
63 | struct mic_bootparam *bootparam = mdev->dp; | ||
64 | |||
65 | bootparam->magic = MIC_MAGIC; | ||
66 | bootparam->c2h_shutdown_db = mdev->shutdown_db; | ||
67 | bootparam->h2c_shutdown_db = -1; | ||
68 | bootparam->h2c_config_db = -1; | ||
69 | bootparam->shutdown_status = 0; | ||
70 | bootparam->shutdown_card = 0; | ||
71 | } | ||
72 | |||
73 | /** | ||
74 | * mic_start - Start the MIC. | ||
75 | * @mdev: pointer to mic_device instance | ||
76 | * @buf: buffer containing boot string including firmware/ramdisk path. | ||
77 | * | ||
78 | * This function prepares an MIC for boot and initiates boot. | ||
79 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
80 | */ | ||
81 | int mic_start(struct mic_device *mdev, const char *buf) | ||
82 | { | ||
83 | int rc; | ||
84 | mutex_lock(&mdev->mic_mutex); | ||
85 | retry: | ||
86 | if (MIC_OFFLINE != mdev->state) { | ||
87 | rc = -EINVAL; | ||
88 | goto unlock_ret; | ||
89 | } | ||
90 | if (!mdev->ops->is_fw_ready(mdev)) { | ||
91 | mic_reset(mdev); | ||
92 | /* | ||
93 | * The state will either be MIC_OFFLINE if the reset succeeded | ||
94 | * or MIC_RESET_FAILED if the firmware reset failed. | ||
95 | */ | ||
96 | goto retry; | ||
97 | } | ||
98 | rc = mdev->ops->load_mic_fw(mdev, buf); | ||
99 | if (rc) | ||
100 | goto unlock_ret; | ||
101 | mic_smpt_restore(mdev); | ||
102 | mic_intr_restore(mdev); | ||
103 | mdev->intr_ops->enable_interrupts(mdev); | ||
104 | mdev->ops->write_spad(mdev, MIC_DPLO_SPAD, mdev->dp_dma_addr); | ||
105 | mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); | ||
106 | mdev->ops->send_firmware_intr(mdev); | ||
107 | mic_set_state(mdev, MIC_ONLINE); | ||
108 | unlock_ret: | ||
109 | mutex_unlock(&mdev->mic_mutex); | ||
110 | return rc; | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * mic_stop - Prepare the MIC for reset and trigger reset. | ||
115 | * @mdev: pointer to mic_device instance | ||
116 | * @force: force a MIC to reset even if it is already offline. | ||
117 | * | ||
118 | * RETURNS: None. | ||
119 | */ | ||
120 | void mic_stop(struct mic_device *mdev, bool force) | ||
121 | { | ||
122 | mutex_lock(&mdev->mic_mutex); | ||
123 | if (MIC_OFFLINE != mdev->state || force) { | ||
124 | mic_virtio_reset_devices(mdev); | ||
125 | mic_bootparam_init(mdev); | ||
126 | mic_reset(mdev); | ||
127 | if (MIC_RESET_FAILED == mdev->state) | ||
128 | goto unlock; | ||
129 | mic_set_shutdown_status(mdev, MIC_NOP); | ||
130 | if (MIC_SUSPENDED != mdev->state) | ||
131 | mic_set_state(mdev, MIC_OFFLINE); | ||
132 | } | ||
133 | unlock: | ||
134 | mutex_unlock(&mdev->mic_mutex); | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * mic_shutdown - Initiate MIC shutdown. | ||
139 | * @mdev: pointer to mic_device instance | ||
140 | * | ||
141 | * RETURNS: None. | ||
142 | */ | ||
143 | void mic_shutdown(struct mic_device *mdev) | ||
144 | { | ||
145 | struct mic_bootparam *bootparam = mdev->dp; | ||
146 | s8 db = bootparam->h2c_shutdown_db; | ||
147 | |||
148 | mutex_lock(&mdev->mic_mutex); | ||
149 | if (MIC_ONLINE == mdev->state && db != -1) { | ||
150 | bootparam->shutdown_card = 1; | ||
151 | mdev->ops->send_intr(mdev, db); | ||
152 | mic_set_state(mdev, MIC_SHUTTING_DOWN); | ||
153 | } | ||
154 | mutex_unlock(&mdev->mic_mutex); | ||
155 | } | ||
156 | |||
157 | /** | ||
158 | * mic_shutdown_work - Handle shutdown interrupt from MIC. | ||
159 | * @work: The work structure. | ||
160 | * | ||
161 | * This work is scheduled whenever the host has received a shutdown | ||
162 | * interrupt from the MIC. | ||
163 | */ | ||
164 | void mic_shutdown_work(struct work_struct *work) | ||
165 | { | ||
166 | struct mic_device *mdev = container_of(work, struct mic_device, | ||
167 | shutdown_work); | ||
168 | struct mic_bootparam *bootparam = mdev->dp; | ||
169 | |||
170 | mutex_lock(&mdev->mic_mutex); | ||
171 | mic_set_shutdown_status(mdev, bootparam->shutdown_status); | ||
172 | bootparam->shutdown_status = 0; | ||
173 | |||
174 | /* | ||
175 | * if state is MIC_SUSPENDED, OSPM suspend is in progress. We do not | ||
176 | * change the state here so as to prevent users from booting the card | ||
177 | * during and after the suspend operation. | ||
178 | */ | ||
179 | if (MIC_SHUTTING_DOWN != mdev->state && | ||
180 | MIC_SUSPENDED != mdev->state) | ||
181 | mic_set_state(mdev, MIC_SHUTTING_DOWN); | ||
182 | mutex_unlock(&mdev->mic_mutex); | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * mic_reset_trigger_work - Trigger MIC reset. | ||
187 | * @work: The work structure. | ||
188 | * | ||
189 | * This work is scheduled whenever the host wants to reset the MIC. | ||
190 | */ | ||
191 | void mic_reset_trigger_work(struct work_struct *work) | ||
192 | { | ||
193 | struct mic_device *mdev = container_of(work, struct mic_device, | ||
194 | reset_trigger_work); | ||
195 | |||
196 | mic_stop(mdev, false); | ||
197 | } | ||
198 | |||
199 | /** | ||
200 | * mic_complete_resume - Complete MIC Resume after an OSPM suspend/hibernate | ||
201 | * event. | ||
202 | * @mdev: pointer to mic_device instance | ||
203 | * | ||
204 | * RETURNS: None. | ||
205 | */ | ||
206 | void mic_complete_resume(struct mic_device *mdev) | ||
207 | { | ||
208 | if (mdev->state != MIC_SUSPENDED) { | ||
209 | dev_warn(mdev->sdev->parent, "state %d should be %d\n", | ||
210 | mdev->state, MIC_SUSPENDED); | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | /* Make sure firmware is ready */ | ||
215 | if (!mdev->ops->is_fw_ready(mdev)) | ||
216 | mic_stop(mdev, true); | ||
217 | |||
218 | mutex_lock(&mdev->mic_mutex); | ||
219 | mic_set_state(mdev, MIC_OFFLINE); | ||
220 | mutex_unlock(&mdev->mic_mutex); | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * mic_prepare_suspend - Handle suspend notification for the MIC device. | ||
225 | * @mdev: pointer to mic_device instance | ||
226 | * | ||
227 | * RETURNS: None. | ||
228 | */ | ||
229 | void mic_prepare_suspend(struct mic_device *mdev) | ||
230 | { | ||
231 | int rc; | ||
232 | |||
233 | #define MIC_SUSPEND_TIMEOUT (60 * HZ) | ||
234 | |||
235 | mutex_lock(&mdev->mic_mutex); | ||
236 | switch (mdev->state) { | ||
237 | case MIC_OFFLINE: | ||
238 | /* | ||
239 | * Card is already offline. Set state to MIC_SUSPENDED | ||
240 | * to prevent users from booting the card. | ||
241 | */ | ||
242 | mic_set_state(mdev, MIC_SUSPENDED); | ||
243 | mutex_unlock(&mdev->mic_mutex); | ||
244 | break; | ||
245 | case MIC_ONLINE: | ||
246 | /* | ||
247 | * Card is online. Set state to MIC_SUSPENDING and notify | ||
248 | * MIC user space daemon which will issue card | ||
249 | * shutdown and reset. | ||
250 | */ | ||
251 | mic_set_state(mdev, MIC_SUSPENDING); | ||
252 | mutex_unlock(&mdev->mic_mutex); | ||
253 | rc = wait_for_completion_timeout(&mdev->reset_wait, | ||
254 | MIC_SUSPEND_TIMEOUT); | ||
255 | /* Force reset the card if the shutdown completion timed out */ | ||
256 | if (!rc) { | ||
257 | mutex_lock(&mdev->mic_mutex); | ||
258 | mic_set_state(mdev, MIC_SUSPENDED); | ||
259 | mutex_unlock(&mdev->mic_mutex); | ||
260 | mic_stop(mdev, true); | ||
261 | } | ||
262 | break; | ||
263 | case MIC_SHUTTING_DOWN: | ||
264 | /* | ||
265 | * Card is shutting down. Set state to MIC_SUSPENDED | ||
266 | * to prevent further boot of the card. | ||
267 | */ | ||
268 | mic_set_state(mdev, MIC_SUSPENDED); | ||
269 | mutex_unlock(&mdev->mic_mutex); | ||
270 | rc = wait_for_completion_timeout(&mdev->reset_wait, | ||
271 | MIC_SUSPEND_TIMEOUT); | ||
272 | /* Force reset the card if the shutdown completion timed out */ | ||
273 | if (!rc) | ||
274 | mic_stop(mdev, true); | ||
275 | break; | ||
276 | default: | ||
277 | mutex_unlock(&mdev->mic_mutex); | ||
278 | break; | ||
279 | } | ||
280 | } | ||
281 | |||
282 | /** | ||
283 | * mic_suspend - Initiate MIC suspend. Suspend merely issues card shutdown. | ||
284 | * @mdev: pointer to mic_device instance | ||
285 | * | ||
286 | * RETURNS: None. | ||
287 | */ | ||
288 | void mic_suspend(struct mic_device *mdev) | ||
289 | { | ||
290 | struct mic_bootparam *bootparam = mdev->dp; | ||
291 | s8 db = bootparam->h2c_shutdown_db; | ||
292 | |||
293 | mutex_lock(&mdev->mic_mutex); | ||
294 | if (MIC_SUSPENDING == mdev->state && db != -1) { | ||
295 | bootparam->shutdown_card = 1; | ||
296 | mdev->ops->send_intr(mdev, db); | ||
297 | mic_set_state(mdev, MIC_SUSPENDED); | ||
298 | } | ||
299 | mutex_unlock(&mdev->mic_mutex); | ||
300 | } | ||
diff --git a/drivers/misc/mic/host/mic_debugfs.c b/drivers/misc/mic/host/mic_debugfs.c new file mode 100644 index 000000000000..028ba5d6fd1c --- /dev/null +++ b/drivers/misc/mic/host/mic_debugfs.c | |||
@@ -0,0 +1,491 @@ | |||
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_dev.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, desc->next); | ||
325 | desc++; | ||
326 | } | ||
327 | avail = vrh->vring.avail; | ||
328 | seq_printf(s, "avail flags 0x%x idx %d\n", | ||
329 | avail->flags, avail->idx & (num - 1)); | ||
330 | seq_printf(s, "avail flags 0x%x idx %d\n", | ||
331 | avail->flags, avail->idx); | ||
332 | for (j = 0; j < num; j++) | ||
333 | seq_printf(s, "avail ring[%d] %d\n", | ||
334 | j, avail->ring[j]); | ||
335 | used = vrh->vring.used; | ||
336 | seq_printf(s, "used flags 0x%x idx %d\n", | ||
337 | used->flags, used->idx & (num - 1)); | ||
338 | seq_printf(s, "used flags 0x%x idx %d\n", | ||
339 | used->flags, used->idx); | ||
340 | for (j = 0; j < num; j++) | ||
341 | seq_printf(s, "used ring[%d] id %d len %d\n", | ||
342 | j, used->ring[j].id, | ||
343 | 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] & | ||
404 | BIT(j)) ? 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 | static int mic_msi_irq_info_debug_open(struct inode *inode, struct file *file) | ||
415 | { | ||
416 | return single_open(file, mic_msi_irq_info_show, inode->i_private); | ||
417 | } | ||
418 | |||
419 | static int | ||
420 | mic_msi_irq_info_debug_release(struct inode *inode, struct file *file) | ||
421 | { | ||
422 | return single_release(inode, file); | ||
423 | } | ||
424 | |||
425 | static const struct file_operations msi_irq_info_ops = { | ||
426 | .owner = THIS_MODULE, | ||
427 | .open = mic_msi_irq_info_debug_open, | ||
428 | .read = seq_read, | ||
429 | .llseek = seq_lseek, | ||
430 | .release = mic_msi_irq_info_debug_release | ||
431 | }; | ||
432 | |||
433 | /** | ||
434 | * mic_create_debug_dir - Initialize MIC debugfs entries. | ||
435 | */ | ||
436 | void mic_create_debug_dir(struct mic_device *mdev) | ||
437 | { | ||
438 | if (!mic_dbg) | ||
439 | return; | ||
440 | |||
441 | mdev->dbg_dir = debugfs_create_dir(dev_name(mdev->sdev), mic_dbg); | ||
442 | if (!mdev->dbg_dir) | ||
443 | return; | ||
444 | |||
445 | debugfs_create_file("log_buf", 0444, mdev->dbg_dir, mdev, &log_buf_ops); | ||
446 | |||
447 | debugfs_create_file("smpt", 0444, mdev->dbg_dir, mdev, &smpt_file_ops); | ||
448 | |||
449 | debugfs_create_file("soft_reset", 0444, mdev->dbg_dir, mdev, | ||
450 | &soft_reset_ops); | ||
451 | |||
452 | debugfs_create_file("post_code", 0444, mdev->dbg_dir, mdev, | ||
453 | &post_code_ops); | ||
454 | |||
455 | debugfs_create_file("dp", 0444, mdev->dbg_dir, mdev, &dp_ops); | ||
456 | |||
457 | debugfs_create_file("vdev_info", 0444, mdev->dbg_dir, mdev, | ||
458 | &vdev_info_ops); | ||
459 | |||
460 | debugfs_create_file("msi_irq_info", 0444, mdev->dbg_dir, mdev, | ||
461 | &msi_irq_info_ops); | ||
462 | } | ||
463 | |||
464 | /** | ||
465 | * mic_delete_debug_dir - Uninitialize MIC debugfs entries. | ||
466 | */ | ||
467 | void mic_delete_debug_dir(struct mic_device *mdev) | ||
468 | { | ||
469 | if (!mdev->dbg_dir) | ||
470 | return; | ||
471 | |||
472 | debugfs_remove_recursive(mdev->dbg_dir); | ||
473 | } | ||
474 | |||
475 | /** | ||
476 | * mic_init_debugfs - Initialize global debugfs entry. | ||
477 | */ | ||
478 | void __init mic_init_debugfs(void) | ||
479 | { | ||
480 | mic_dbg = debugfs_create_dir(KBUILD_MODNAME, NULL); | ||
481 | if (!mic_dbg) | ||
482 | pr_err("can't create debugfs dir\n"); | ||
483 | } | ||
484 | |||
485 | /** | ||
486 | * mic_exit_debugfs - Uninitialize global debugfs entry | ||
487 | */ | ||
488 | void mic_exit_debugfs(void) | ||
489 | { | ||
490 | debugfs_remove(mic_dbg); | ||
491 | } | ||
diff --git a/drivers/misc/mic/host/mic_device.h b/drivers/misc/mic/host/mic_device.h new file mode 100644 index 000000000000..3574cc375bb9 --- /dev/null +++ b/drivers/misc/mic/host/mic_device.h | |||
@@ -0,0 +1,203 @@ | |||
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 | #include <linux/notifier.h> | ||
27 | |||
28 | #include "mic_intr.h" | ||
29 | |||
30 | /* The maximum number of MIC devices supported in a single host system. */ | ||
31 | #define MIC_MAX_NUM_DEVS 256 | ||
32 | |||
33 | /** | ||
34 | * enum mic_hw_family - The hardware family to which a device belongs. | ||
35 | */ | ||
36 | enum mic_hw_family { | ||
37 | MIC_FAMILY_X100 = 0, | ||
38 | MIC_FAMILY_UNKNOWN | ||
39 | }; | ||
40 | |||
41 | /** | ||
42 | * enum mic_stepping - MIC stepping ids. | ||
43 | */ | ||
44 | enum mic_stepping { | ||
45 | MIC_A0_STEP = 0x0, | ||
46 | MIC_B0_STEP = 0x10, | ||
47 | MIC_B1_STEP = 0x11, | ||
48 | MIC_C0_STEP = 0x20, | ||
49 | }; | ||
50 | |||
51 | /** | ||
52 | * struct mic_device - MIC device information for each card. | ||
53 | * | ||
54 | * @mmio: MMIO bar information. | ||
55 | * @aper: Aperture bar information. | ||
56 | * @family: The MIC family to which this device belongs. | ||
57 | * @ops: MIC HW specific operations. | ||
58 | * @id: The unique device id for this MIC device. | ||
59 | * @stepping: Stepping ID. | ||
60 | * @attr_group: Pointer to list of sysfs attribute groups. | ||
61 | * @sdev: Device for sysfs entries. | ||
62 | * @mic_mutex: Mutex for synchronizing access to mic_device. | ||
63 | * @intr_ops: HW specific interrupt operations. | ||
64 | * @smpt_ops: Hardware specific SMPT operations. | ||
65 | * @smpt: MIC SMPT information. | ||
66 | * @intr_info: H/W specific interrupt information. | ||
67 | * @irq_info: The OS specific irq information | ||
68 | * @dbg_dir: debugfs directory of this MIC device. | ||
69 | * @cmdline: Kernel command line. | ||
70 | * @firmware: Firmware file name. | ||
71 | * @ramdisk: Ramdisk file name. | ||
72 | * @bootmode: Boot mode i.e. "linux" or "elf" for flash updates. | ||
73 | * @bootaddr: MIC boot address. | ||
74 | * @reset_trigger_work: Work for triggering reset requests. | ||
75 | * @shutdown_work: Work for handling shutdown interrupts. | ||
76 | * @state: MIC state. | ||
77 | * @shutdown_status: MIC status reported by card for shutdown/crashes. | ||
78 | * @state_sysfs: Sysfs dirent for notifying ring 3 about MIC state changes. | ||
79 | * @reset_wait: Waitqueue for sleeping while reset completes. | ||
80 | * @log_buf_addr: Log buffer address for MIC. | ||
81 | * @log_buf_len: Log buffer length address for MIC. | ||
82 | * @dp: virtio device page | ||
83 | * @dp_dma_addr: virtio device page DMA address. | ||
84 | * @shutdown_db: shutdown doorbell. | ||
85 | * @shutdown_cookie: shutdown cookie. | ||
86 | * @cdev: Character device for MIC. | ||
87 | * @vdev_list: list of virtio devices. | ||
88 | * @pm_notifier: Handles PM notifications from the OS. | ||
89 | */ | ||
90 | struct mic_device { | ||
91 | struct mic_mw mmio; | ||
92 | struct mic_mw aper; | ||
93 | enum mic_hw_family family; | ||
94 | struct mic_hw_ops *ops; | ||
95 | int id; | ||
96 | enum mic_stepping stepping; | ||
97 | const struct attribute_group **attr_group; | ||
98 | struct device *sdev; | ||
99 | struct mutex mic_mutex; | ||
100 | struct mic_hw_intr_ops *intr_ops; | ||
101 | struct mic_smpt_ops *smpt_ops; | ||
102 | struct mic_smpt_info *smpt; | ||
103 | struct mic_intr_info *intr_info; | ||
104 | struct mic_irq_info irq_info; | ||
105 | struct dentry *dbg_dir; | ||
106 | char *cmdline; | ||
107 | char *firmware; | ||
108 | char *ramdisk; | ||
109 | char *bootmode; | ||
110 | u32 bootaddr; | ||
111 | struct work_struct reset_trigger_work; | ||
112 | struct work_struct shutdown_work; | ||
113 | u8 state; | ||
114 | u8 shutdown_status; | ||
115 | struct sysfs_dirent *state_sysfs; | ||
116 | struct completion reset_wait; | ||
117 | void *log_buf_addr; | ||
118 | int *log_buf_len; | ||
119 | void *dp; | ||
120 | dma_addr_t dp_dma_addr; | ||
121 | int shutdown_db; | ||
122 | struct mic_irq *shutdown_cookie; | ||
123 | struct cdev cdev; | ||
124 | struct list_head vdev_list; | ||
125 | struct notifier_block pm_notifier; | ||
126 | }; | ||
127 | |||
128 | /** | ||
129 | * struct mic_hw_ops - MIC HW specific operations. | ||
130 | * @aper_bar: Aperture bar resource number. | ||
131 | * @mmio_bar: MMIO bar resource number. | ||
132 | * @read_spad: Read from scratch pad register. | ||
133 | * @write_spad: Write to scratch pad register. | ||
134 | * @send_intr: Send an interrupt for a particular doorbell on the card. | ||
135 | * @ack_interrupt: Hardware specific operations to ack the h/w on | ||
136 | * receipt of an interrupt. | ||
137 | * @reset: Reset the remote processor. | ||
138 | * @reset_fw_ready: Reset firmware ready field. | ||
139 | * @is_fw_ready: Check if firmware is ready for OS download. | ||
140 | * @send_firmware_intr: Send an interrupt to the card firmware. | ||
141 | * @load_mic_fw: Load firmware segments required to boot the card | ||
142 | * into card memory. This includes the kernel, command line, ramdisk etc. | ||
143 | * @get_postcode: Get post code status from firmware. | ||
144 | */ | ||
145 | struct mic_hw_ops { | ||
146 | u8 aper_bar; | ||
147 | u8 mmio_bar; | ||
148 | u32 (*read_spad)(struct mic_device *mdev, unsigned int idx); | ||
149 | void (*write_spad)(struct mic_device *mdev, unsigned int idx, u32 val); | ||
150 | void (*send_intr)(struct mic_device *mdev, int doorbell); | ||
151 | u32 (*ack_interrupt)(struct mic_device *mdev); | ||
152 | void (*reset)(struct mic_device *mdev); | ||
153 | void (*reset_fw_ready)(struct mic_device *mdev); | ||
154 | bool (*is_fw_ready)(struct mic_device *mdev); | ||
155 | void (*send_firmware_intr)(struct mic_device *mdev); | ||
156 | int (*load_mic_fw)(struct mic_device *mdev, const char *buf); | ||
157 | u32 (*get_postcode)(struct mic_device *mdev); | ||
158 | }; | ||
159 | |||
160 | /** | ||
161 | * mic_mmio_read - read from an MMIO register. | ||
162 | * @mw: MMIO register base virtual address. | ||
163 | * @offset: register offset. | ||
164 | * | ||
165 | * RETURNS: register value. | ||
166 | */ | ||
167 | static inline u32 mic_mmio_read(struct mic_mw *mw, u32 offset) | ||
168 | { | ||
169 | return ioread32(mw->va + offset); | ||
170 | } | ||
171 | |||
172 | /** | ||
173 | * mic_mmio_write - write to an MMIO register. | ||
174 | * @mw: MMIO register base virtual address. | ||
175 | * @val: the data value to put into the register | ||
176 | * @offset: register offset. | ||
177 | * | ||
178 | * RETURNS: none. | ||
179 | */ | ||
180 | static inline void | ||
181 | mic_mmio_write(struct mic_mw *mw, u32 val, u32 offset) | ||
182 | { | ||
183 | iowrite32(val, mw->va + offset); | ||
184 | } | ||
185 | |||
186 | void mic_sysfs_init(struct mic_device *mdev); | ||
187 | int mic_start(struct mic_device *mdev, const char *buf); | ||
188 | void mic_stop(struct mic_device *mdev, bool force); | ||
189 | void mic_shutdown(struct mic_device *mdev); | ||
190 | void mic_reset_delayed_work(struct work_struct *work); | ||
191 | void mic_reset_trigger_work(struct work_struct *work); | ||
192 | void mic_shutdown_work(struct work_struct *work); | ||
193 | void mic_bootparam_init(struct mic_device *mdev); | ||
194 | void mic_set_state(struct mic_device *mdev, u8 state); | ||
195 | void mic_set_shutdown_status(struct mic_device *mdev, u8 status); | ||
196 | void mic_create_debug_dir(struct mic_device *dev); | ||
197 | void mic_delete_debug_dir(struct mic_device *dev); | ||
198 | void __init mic_init_debugfs(void); | ||
199 | void mic_exit_debugfs(void); | ||
200 | void mic_prepare_suspend(struct mic_device *mdev); | ||
201 | void mic_complete_resume(struct mic_device *mdev); | ||
202 | void mic_suspend(struct mic_device *mdev); | ||
203 | #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..85776d7327f3 --- /dev/null +++ b/drivers/misc/mic/host/mic_fops.c | |||
@@ -0,0 +1,222 @@ | |||
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 | #include <linux/pci.h> | ||
23 | |||
24 | #include <linux/mic_common.h> | ||
25 | #include "../common/mic_dev.h" | ||
26 | #include "mic_device.h" | ||
27 | #include "mic_fops.h" | ||
28 | #include "mic_virtio.h" | ||
29 | |||
30 | int mic_open(struct inode *inode, struct file *f) | ||
31 | { | ||
32 | struct mic_vdev *mvdev; | ||
33 | struct mic_device *mdev = container_of(inode->i_cdev, | ||
34 | struct mic_device, cdev); | ||
35 | |||
36 | mvdev = kzalloc(sizeof(*mvdev), GFP_KERNEL); | ||
37 | if (!mvdev) | ||
38 | return -ENOMEM; | ||
39 | |||
40 | init_waitqueue_head(&mvdev->waitq); | ||
41 | INIT_LIST_HEAD(&mvdev->list); | ||
42 | mvdev->mdev = mdev; | ||
43 | mvdev->virtio_id = -1; | ||
44 | |||
45 | f->private_data = mvdev; | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | int mic_release(struct inode *inode, struct file *f) | ||
50 | { | ||
51 | struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data; | ||
52 | |||
53 | if (-1 != mvdev->virtio_id) | ||
54 | mic_virtio_del_device(mvdev); | ||
55 | f->private_data = NULL; | ||
56 | kfree(mvdev); | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | long mic_ioctl(struct file *f, unsigned int cmd, unsigned long arg) | ||
61 | { | ||
62 | struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data; | ||
63 | void __user *argp = (void __user *)arg; | ||
64 | int ret; | ||
65 | |||
66 | switch (cmd) { | ||
67 | case MIC_VIRTIO_ADD_DEVICE: | ||
68 | { | ||
69 | ret = mic_virtio_add_device(mvdev, argp); | ||
70 | if (ret < 0) { | ||
71 | dev_err(mic_dev(mvdev), | ||
72 | "%s %d errno ret %d\n", | ||
73 | __func__, __LINE__, ret); | ||
74 | return ret; | ||
75 | } | ||
76 | break; | ||
77 | } | ||
78 | case MIC_VIRTIO_COPY_DESC: | ||
79 | { | ||
80 | struct mic_copy_desc copy; | ||
81 | |||
82 | ret = mic_vdev_inited(mvdev); | ||
83 | if (ret) | ||
84 | return ret; | ||
85 | |||
86 | if (copy_from_user(©, argp, sizeof(copy))) | ||
87 | return -EFAULT; | ||
88 | |||
89 | dev_dbg(mic_dev(mvdev), | ||
90 | "%s %d === iovcnt 0x%x vr_idx 0x%x update_used %d\n", | ||
91 | __func__, __LINE__, copy.iovcnt, copy.vr_idx, | ||
92 | copy.update_used); | ||
93 | |||
94 | ret = mic_virtio_copy_desc(mvdev, ©); | ||
95 | if (ret < 0) { | ||
96 | dev_err(mic_dev(mvdev), | ||
97 | "%s %d errno ret %d\n", | ||
98 | __func__, __LINE__, ret); | ||
99 | return ret; | ||
100 | } | ||
101 | if (copy_to_user( | ||
102 | &((struct mic_copy_desc __user *)argp)->out_len, | ||
103 | ©.out_len, sizeof(copy.out_len))) { | ||
104 | dev_err(mic_dev(mvdev), "%s %d errno ret %d\n", | ||
105 | __func__, __LINE__, -EFAULT); | ||
106 | return -EFAULT; | ||
107 | } | ||
108 | break; | ||
109 | } | ||
110 | case MIC_VIRTIO_CONFIG_CHANGE: | ||
111 | { | ||
112 | ret = mic_vdev_inited(mvdev); | ||
113 | if (ret) | ||
114 | return ret; | ||
115 | |||
116 | ret = mic_virtio_config_change(mvdev, argp); | ||
117 | if (ret < 0) { | ||
118 | dev_err(mic_dev(mvdev), | ||
119 | "%s %d errno ret %d\n", | ||
120 | __func__, __LINE__, ret); | ||
121 | return ret; | ||
122 | } | ||
123 | break; | ||
124 | } | ||
125 | default: | ||
126 | return -ENOIOCTLCMD; | ||
127 | }; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * We return POLLIN | POLLOUT from poll when new buffers are enqueued, and | ||
133 | * not when previously enqueued buffers may be available. This means that | ||
134 | * in the card->host (TX) path, when userspace is unblocked by poll it | ||
135 | * must drain all available descriptors or it can stall. | ||
136 | */ | ||
137 | unsigned int mic_poll(struct file *f, poll_table *wait) | ||
138 | { | ||
139 | struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data; | ||
140 | int mask = 0; | ||
141 | |||
142 | poll_wait(f, &mvdev->waitq, wait); | ||
143 | |||
144 | if (mic_vdev_inited(mvdev)) { | ||
145 | mask = POLLERR; | ||
146 | } else if (mvdev->poll_wake) { | ||
147 | mvdev->poll_wake = 0; | ||
148 | mask = POLLIN | POLLOUT; | ||
149 | } | ||
150 | |||
151 | return mask; | ||
152 | } | ||
153 | |||
154 | static inline int | ||
155 | mic_query_offset(struct mic_vdev *mvdev, unsigned long offset, | ||
156 | unsigned long *size, unsigned long *pa) | ||
157 | { | ||
158 | struct mic_device *mdev = mvdev->mdev; | ||
159 | unsigned long start = MIC_DP_SIZE; | ||
160 | int i; | ||
161 | |||
162 | /* | ||
163 | * MMAP interface is as follows: | ||
164 | * offset region | ||
165 | * 0x0 virtio device_page | ||
166 | * 0x1000 first vring | ||
167 | * 0x1000 + size of 1st vring second vring | ||
168 | * .... | ||
169 | */ | ||
170 | if (!offset) { | ||
171 | *pa = virt_to_phys(mdev->dp); | ||
172 | *size = MIC_DP_SIZE; | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | for (i = 0; i < mvdev->dd->num_vq; i++) { | ||
177 | struct mic_vringh *mvr = &mvdev->mvr[i]; | ||
178 | if (offset == start) { | ||
179 | *pa = virt_to_phys(mvr->vring.va); | ||
180 | *size = mvr->vring.len; | ||
181 | return 0; | ||
182 | } | ||
183 | start += mvr->vring.len; | ||
184 | } | ||
185 | return -1; | ||
186 | } | ||
187 | |||
188 | /* | ||
189 | * Maps the device page and virtio rings to user space for readonly access. | ||
190 | */ | ||
191 | int | ||
192 | mic_mmap(struct file *f, struct vm_area_struct *vma) | ||
193 | { | ||
194 | struct mic_vdev *mvdev = (struct mic_vdev *)f->private_data; | ||
195 | unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; | ||
196 | unsigned long pa, size = vma->vm_end - vma->vm_start, size_rem = size; | ||
197 | int i, err; | ||
198 | |||
199 | err = mic_vdev_inited(mvdev); | ||
200 | if (err) | ||
201 | return err; | ||
202 | |||
203 | if (vma->vm_flags & VM_WRITE) | ||
204 | return -EACCES; | ||
205 | |||
206 | while (size_rem) { | ||
207 | i = mic_query_offset(mvdev, offset, &size, &pa); | ||
208 | if (i < 0) | ||
209 | return -EINVAL; | ||
210 | err = remap_pfn_range(vma, vma->vm_start + offset, | ||
211 | pa >> PAGE_SHIFT, size, vma->vm_page_prot); | ||
212 | if (err) | ||
213 | return err; | ||
214 | dev_dbg(mic_dev(mvdev), | ||
215 | "%s %d type %d size 0x%lx off 0x%lx pa 0x%lx vma 0x%lx\n", | ||
216 | __func__, __LINE__, mvdev->virtio_id, size, offset, | ||
217 | pa, vma->vm_start + offset); | ||
218 | size_rem -= size; | ||
219 | offset += size; | ||
220 | } | ||
221 | return 0; | ||
222 | } | ||
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..f9c29bc918bc --- /dev/null +++ b/drivers/misc/mic/host/mic_intr.c | |||
@@ -0,0 +1,630 @@ | |||
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_dev.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(*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 | int entry_size = sizeof(*mdev->irq_info.msix_entries); | ||
186 | |||
187 | mdev->irq_info.msix_entries = kmalloc_array(MIC_MIN_MSIX, | ||
188 | entry_size, GFP_KERNEL); | ||
189 | if (!mdev->irq_info.msix_entries) { | ||
190 | rc = -ENOMEM; | ||
191 | goto err_nomem1; | ||
192 | } | ||
193 | |||
194 | for (i = 0; i < MIC_MIN_MSIX; i++) | ||
195 | mdev->irq_info.msix_entries[i].entry = i; | ||
196 | |||
197 | rc = pci_enable_msix(pdev, mdev->irq_info.msix_entries, | ||
198 | MIC_MIN_MSIX); | ||
199 | if (rc) { | ||
200 | dev_dbg(&pdev->dev, "Error enabling MSIx. rc = %d\n", rc); | ||
201 | goto err_enable_msix; | ||
202 | } | ||
203 | |||
204 | mdev->irq_info.num_vectors = MIC_MIN_MSIX; | ||
205 | mdev->irq_info.mic_msi_map = kzalloc((sizeof(u32) * | ||
206 | mdev->irq_info.num_vectors), GFP_KERNEL); | ||
207 | |||
208 | if (!mdev->irq_info.mic_msi_map) { | ||
209 | rc = -ENOMEM; | ||
210 | goto err_nomem2; | ||
211 | } | ||
212 | |||
213 | dev_dbg(mdev->sdev->parent, | ||
214 | "%d MSIx irqs setup\n", mdev->irq_info.num_vectors); | ||
215 | return 0; | ||
216 | err_nomem2: | ||
217 | pci_disable_msix(pdev); | ||
218 | err_enable_msix: | ||
219 | kfree(mdev->irq_info.msix_entries); | ||
220 | err_nomem1: | ||
221 | mdev->irq_info.num_vectors = 0; | ||
222 | return rc; | ||
223 | } | ||
224 | |||
225 | /** | ||
226 | * mic_setup_callbacks - Initialize data structures needed | ||
227 | * to handle callbacks. | ||
228 | * | ||
229 | * @mdev: pointer to mic_device instance | ||
230 | */ | ||
231 | static int mic_setup_callbacks(struct mic_device *mdev) | ||
232 | { | ||
233 | int i; | ||
234 | |||
235 | mdev->irq_info.cb_list = kmalloc_array(MIC_NUM_OFFSETS, | ||
236 | sizeof(*mdev->irq_info.cb_list), | ||
237 | GFP_KERNEL); | ||
238 | if (!mdev->irq_info.cb_list) | ||
239 | return -ENOMEM; | ||
240 | |||
241 | for (i = 0; i < MIC_NUM_OFFSETS; i++) | ||
242 | INIT_LIST_HEAD(&mdev->irq_info.cb_list[i]); | ||
243 | ida_init(&mdev->irq_info.cb_ida); | ||
244 | spin_lock_init(&mdev->irq_info.mic_intr_lock); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * mic_release_callbacks - Uninitialize data structures needed | ||
250 | * to handle callbacks. | ||
251 | * | ||
252 | * @mdev: pointer to mic_device instance | ||
253 | */ | ||
254 | static void mic_release_callbacks(struct mic_device *mdev) | ||
255 | { | ||
256 | unsigned long flags; | ||
257 | struct list_head *pos, *tmp; | ||
258 | struct mic_intr_cb *intr_cb; | ||
259 | int i; | ||
260 | |||
261 | for (i = 0; i < MIC_NUM_OFFSETS; i++) { | ||
262 | spin_lock_irqsave(&mdev->irq_info.mic_intr_lock, flags); | ||
263 | |||
264 | if (list_empty(&mdev->irq_info.cb_list[i])) { | ||
265 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, | ||
266 | flags); | ||
267 | break; | ||
268 | } | ||
269 | |||
270 | list_for_each_safe(pos, tmp, &mdev->irq_info.cb_list[i]) { | ||
271 | intr_cb = list_entry(pos, struct mic_intr_cb, list); | ||
272 | list_del(pos); | ||
273 | ida_simple_remove(&mdev->irq_info.cb_ida, | ||
274 | intr_cb->cb_id); | ||
275 | kfree(intr_cb); | ||
276 | } | ||
277 | spin_unlock_irqrestore(&mdev->irq_info.mic_intr_lock, flags); | ||
278 | } | ||
279 | ida_destroy(&mdev->irq_info.cb_ida); | ||
280 | kfree(mdev->irq_info.cb_list); | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * mic_setup_msi - Initializes MSI interrupts. | ||
285 | * | ||
286 | * @mdev: pointer to mic_device instance | ||
287 | * @pdev: PCI device structure | ||
288 | * | ||
289 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
290 | */ | ||
291 | static int mic_setup_msi(struct mic_device *mdev, struct pci_dev *pdev) | ||
292 | { | ||
293 | int rc; | ||
294 | |||
295 | rc = pci_enable_msi(pdev); | ||
296 | if (rc) { | ||
297 | dev_dbg(&pdev->dev, "Error enabling MSI. rc = %d\n", rc); | ||
298 | return rc; | ||
299 | } | ||
300 | |||
301 | mdev->irq_info.num_vectors = 1; | ||
302 | mdev->irq_info.mic_msi_map = kzalloc((sizeof(u32) * | ||
303 | mdev->irq_info.num_vectors), GFP_KERNEL); | ||
304 | |||
305 | if (!mdev->irq_info.mic_msi_map) { | ||
306 | rc = -ENOMEM; | ||
307 | goto err_nomem1; | ||
308 | } | ||
309 | |||
310 | rc = mic_setup_callbacks(mdev); | ||
311 | if (rc) { | ||
312 | dev_err(&pdev->dev, "Error setting up callbacks\n"); | ||
313 | goto err_nomem2; | ||
314 | } | ||
315 | |||
316 | rc = request_irq(pdev->irq, mic_interrupt, 0 , "mic-msi", mdev); | ||
317 | if (rc) { | ||
318 | dev_err(&pdev->dev, "Error allocating MSI interrupt\n"); | ||
319 | goto err_irq_req_fail; | ||
320 | } | ||
321 | |||
322 | dev_dbg(&pdev->dev, "%d MSI irqs setup\n", mdev->irq_info.num_vectors); | ||
323 | return 0; | ||
324 | err_irq_req_fail: | ||
325 | mic_release_callbacks(mdev); | ||
326 | err_nomem2: | ||
327 | kfree(mdev->irq_info.mic_msi_map); | ||
328 | err_nomem1: | ||
329 | pci_disable_msi(pdev); | ||
330 | mdev->irq_info.num_vectors = 0; | ||
331 | return rc; | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * mic_setup_intx - Initializes legacy interrupts. | ||
336 | * | ||
337 | * @mdev: pointer to mic_device instance | ||
338 | * @pdev: PCI device structure | ||
339 | * | ||
340 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
341 | */ | ||
342 | static int mic_setup_intx(struct mic_device *mdev, struct pci_dev *pdev) | ||
343 | { | ||
344 | int rc; | ||
345 | |||
346 | pci_msi_off(pdev); | ||
347 | |||
348 | /* Enable intx */ | ||
349 | pci_intx(pdev, 1); | ||
350 | rc = mic_setup_callbacks(mdev); | ||
351 | if (rc) { | ||
352 | dev_err(&pdev->dev, "Error setting up callbacks\n"); | ||
353 | goto err_nomem; | ||
354 | } | ||
355 | |||
356 | rc = request_irq(pdev->irq, mic_interrupt, | ||
357 | IRQF_SHARED, "mic-intx", mdev); | ||
358 | if (rc) | ||
359 | goto err; | ||
360 | |||
361 | dev_dbg(&pdev->dev, "intx irq setup\n"); | ||
362 | return 0; | ||
363 | err: | ||
364 | mic_release_callbacks(mdev); | ||
365 | err_nomem: | ||
366 | return rc; | ||
367 | } | ||
368 | |||
369 | /** | ||
370 | * mic_next_db - Retrieve the next doorbell interrupt source id. | ||
371 | * The id is picked sequentially from the available pool of | ||
372 | * doorlbell ids. | ||
373 | * | ||
374 | * @mdev: pointer to the mic_device instance. | ||
375 | * | ||
376 | * Returns the next doorbell interrupt source. | ||
377 | */ | ||
378 | int mic_next_db(struct mic_device *mdev) | ||
379 | { | ||
380 | int next_db; | ||
381 | |||
382 | next_db = mdev->irq_info.next_avail_src % | ||
383 | mdev->intr_info->intr_len[MIC_INTR_DB]; | ||
384 | mdev->irq_info.next_avail_src++; | ||
385 | return next_db; | ||
386 | } | ||
387 | |||
388 | #define COOKIE_ID_SHIFT 16 | ||
389 | #define GET_ENTRY(cookie) ((cookie) & 0xFFFF) | ||
390 | #define GET_OFFSET(cookie) ((cookie) >> COOKIE_ID_SHIFT) | ||
391 | #define MK_COOKIE(x, y) ((x) | (y) << COOKIE_ID_SHIFT) | ||
392 | |||
393 | /** | ||
394 | * mic_request_irq - request an irq. mic_mutex needs | ||
395 | * to be held before calling this function. | ||
396 | * | ||
397 | * @mdev: pointer to mic_device instance | ||
398 | * @func: The callback function that handles the interrupt. | ||
399 | * The function needs to call ack_interrupts | ||
400 | * (mdev->ops->ack_interrupt(mdev)) when handling the interrupts. | ||
401 | * @name: The ASCII name of the callee requesting the irq. | ||
402 | * @data: private data that is returned back when calling the | ||
403 | * function handler. | ||
404 | * @intr_src: The source id of the requester. Its the doorbell id | ||
405 | * for Doorbell interrupts and DMA channel id for DMA interrupts. | ||
406 | * @type: The type of interrupt. Values defined in mic_intr_type | ||
407 | * | ||
408 | * returns: The cookie that is transparent to the caller. Passed | ||
409 | * back when calling mic_free_irq. An appropriate error code | ||
410 | * is returned on failure. Caller needs to use IS_ERR(return_val) | ||
411 | * to check for failure and PTR_ERR(return_val) to obtained the | ||
412 | * error code. | ||
413 | * | ||
414 | */ | ||
415 | struct mic_irq *mic_request_irq(struct mic_device *mdev, | ||
416 | irqreturn_t (*func)(int irq, void *dev), | ||
417 | const char *name, void *data, int intr_src, | ||
418 | enum mic_intr_type type) | ||
419 | { | ||
420 | u16 offset; | ||
421 | int rc = 0; | ||
422 | struct msix_entry *msix = NULL; | ||
423 | unsigned long cookie = 0; | ||
424 | u16 entry; | ||
425 | struct mic_intr_cb *intr_cb; | ||
426 | struct pci_dev *pdev = container_of(mdev->sdev->parent, | ||
427 | struct pci_dev, dev); | ||
428 | |||
429 | offset = mic_map_src_to_offset(mdev, intr_src, type); | ||
430 | if (offset >= MIC_NUM_OFFSETS) { | ||
431 | dev_err(mdev->sdev->parent, | ||
432 | "Error mapping index %d to a valid source id.\n", | ||
433 | intr_src); | ||
434 | rc = -EINVAL; | ||
435 | goto err; | ||
436 | } | ||
437 | |||
438 | if (mdev->irq_info.num_vectors > 1) { | ||
439 | msix = mic_get_available_vector(mdev); | ||
440 | if (!msix) { | ||
441 | dev_err(mdev->sdev->parent, | ||
442 | "No MSIx vectors available for use.\n"); | ||
443 | rc = -ENOSPC; | ||
444 | goto err; | ||
445 | } | ||
446 | |||
447 | rc = request_irq(msix->vector, func, 0, name, data); | ||
448 | if (rc) { | ||
449 | dev_dbg(mdev->sdev->parent, | ||
450 | "request irq failed rc = %d\n", rc); | ||
451 | goto err; | ||
452 | } | ||
453 | entry = msix->entry; | ||
454 | mdev->irq_info.mic_msi_map[entry] |= BIT(offset); | ||
455 | mdev->intr_ops->program_msi_to_src_map(mdev, | ||
456 | entry, offset, true); | ||
457 | cookie = MK_COOKIE(entry, offset); | ||
458 | dev_dbg(mdev->sdev->parent, "irq: %d assigned for src: %d\n", | ||
459 | msix->vector, intr_src); | ||
460 | } else { | ||
461 | intr_cb = mic_register_intr_callback(mdev, | ||
462 | offset, func, data); | ||
463 | if (IS_ERR(intr_cb)) { | ||
464 | dev_err(mdev->sdev->parent, | ||
465 | "No available callback entries for use\n"); | ||
466 | rc = PTR_ERR(intr_cb); | ||
467 | goto err; | ||
468 | } | ||
469 | |||
470 | entry = 0; | ||
471 | if (pci_dev_msi_enabled(pdev)) { | ||
472 | mdev->irq_info.mic_msi_map[entry] |= (1 << offset); | ||
473 | mdev->intr_ops->program_msi_to_src_map(mdev, | ||
474 | entry, offset, true); | ||
475 | } | ||
476 | cookie = MK_COOKIE(entry, intr_cb->cb_id); | ||
477 | dev_dbg(mdev->sdev->parent, "callback %d registered for src: %d\n", | ||
478 | intr_cb->cb_id, intr_src); | ||
479 | } | ||
480 | return (struct mic_irq *)cookie; | ||
481 | err: | ||
482 | return ERR_PTR(rc); | ||
483 | } | ||
484 | |||
485 | /** | ||
486 | * mic_free_irq - free irq. mic_mutex | ||
487 | * needs to be held before calling this function. | ||
488 | * | ||
489 | * @mdev: pointer to mic_device instance | ||
490 | * @cookie: cookie obtained during a successful call to mic_request_irq | ||
491 | * @data: private data specified by the calling function during the | ||
492 | * mic_request_irq | ||
493 | * | ||
494 | * returns: none. | ||
495 | */ | ||
496 | void mic_free_irq(struct mic_device *mdev, | ||
497 | struct mic_irq *cookie, void *data) | ||
498 | { | ||
499 | u32 offset; | ||
500 | u32 entry; | ||
501 | u8 src_id; | ||
502 | unsigned int irq; | ||
503 | struct pci_dev *pdev = container_of(mdev->sdev->parent, | ||
504 | struct pci_dev, dev); | ||
505 | |||
506 | entry = GET_ENTRY((unsigned long)cookie); | ||
507 | offset = GET_OFFSET((unsigned long)cookie); | ||
508 | if (mdev->irq_info.num_vectors > 1) { | ||
509 | if (entry >= mdev->irq_info.num_vectors) { | ||
510 | dev_warn(mdev->sdev->parent, | ||
511 | "entry %d should be < num_irq %d\n", | ||
512 | entry, mdev->irq_info.num_vectors); | ||
513 | return; | ||
514 | } | ||
515 | irq = mdev->irq_info.msix_entries[entry].vector; | ||
516 | free_irq(irq, data); | ||
517 | mdev->irq_info.mic_msi_map[entry] &= ~(BIT(offset)); | ||
518 | mdev->intr_ops->program_msi_to_src_map(mdev, | ||
519 | entry, offset, false); | ||
520 | |||
521 | dev_dbg(mdev->sdev->parent, "irq: %d freed\n", irq); | ||
522 | } else { | ||
523 | irq = pdev->irq; | ||
524 | src_id = mic_unregister_intr_callback(mdev, offset); | ||
525 | if (src_id >= MIC_NUM_OFFSETS) { | ||
526 | dev_warn(mdev->sdev->parent, "Error unregistering callback\n"); | ||
527 | return; | ||
528 | } | ||
529 | if (pci_dev_msi_enabled(pdev)) { | ||
530 | mdev->irq_info.mic_msi_map[entry] &= ~(BIT(src_id)); | ||
531 | mdev->intr_ops->program_msi_to_src_map(mdev, | ||
532 | entry, src_id, false); | ||
533 | } | ||
534 | dev_dbg(mdev->sdev->parent, "callback %d unregistered for src: %d\n", | ||
535 | offset, src_id); | ||
536 | } | ||
537 | } | ||
538 | |||
539 | /** | ||
540 | * mic_setup_interrupts - Initializes interrupts. | ||
541 | * | ||
542 | * @mdev: pointer to mic_device instance | ||
543 | * @pdev: PCI device structure | ||
544 | * | ||
545 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
546 | */ | ||
547 | int mic_setup_interrupts(struct mic_device *mdev, struct pci_dev *pdev) | ||
548 | { | ||
549 | int rc; | ||
550 | |||
551 | rc = mic_setup_msix(mdev, pdev); | ||
552 | if (!rc) | ||
553 | goto done; | ||
554 | |||
555 | rc = mic_setup_msi(mdev, pdev); | ||
556 | if (!rc) | ||
557 | goto done; | ||
558 | |||
559 | rc = mic_setup_intx(mdev, pdev); | ||
560 | if (rc) { | ||
561 | dev_err(mdev->sdev->parent, "no usable interrupts\n"); | ||
562 | return rc; | ||
563 | } | ||
564 | done: | ||
565 | mdev->intr_ops->enable_interrupts(mdev); | ||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | /** | ||
570 | * mic_free_interrupts - Frees interrupts setup by mic_setup_interrupts | ||
571 | * | ||
572 | * @mdev: pointer to mic_device instance | ||
573 | * @pdev: PCI device structure | ||
574 | * | ||
575 | * returns none. | ||
576 | */ | ||
577 | void mic_free_interrupts(struct mic_device *mdev, struct pci_dev *pdev) | ||
578 | { | ||
579 | int i; | ||
580 | |||
581 | mdev->intr_ops->disable_interrupts(mdev); | ||
582 | if (mdev->irq_info.num_vectors > 1) { | ||
583 | for (i = 0; i < mdev->irq_info.num_vectors; i++) { | ||
584 | if (mdev->irq_info.mic_msi_map[i]) | ||
585 | dev_warn(&pdev->dev, "irq %d may still be in use.\n", | ||
586 | mdev->irq_info.msix_entries[i].vector); | ||
587 | } | ||
588 | kfree(mdev->irq_info.mic_msi_map); | ||
589 | kfree(mdev->irq_info.msix_entries); | ||
590 | pci_disable_msix(pdev); | ||
591 | } else { | ||
592 | if (pci_dev_msi_enabled(pdev)) { | ||
593 | free_irq(pdev->irq, mdev); | ||
594 | kfree(mdev->irq_info.mic_msi_map); | ||
595 | pci_disable_msi(pdev); | ||
596 | } else { | ||
597 | free_irq(pdev->irq, mdev); | ||
598 | } | ||
599 | mic_release_callbacks(mdev); | ||
600 | } | ||
601 | } | ||
602 | |||
603 | /** | ||
604 | * mic_intr_restore - Restore MIC interrupt registers. | ||
605 | * | ||
606 | * @mdev: pointer to mic_device instance. | ||
607 | * | ||
608 | * Restore the interrupt registers to values previously | ||
609 | * stored in the SW data structures. mic_mutex needs to | ||
610 | * be held before calling this function. | ||
611 | * | ||
612 | * returns None. | ||
613 | */ | ||
614 | void mic_intr_restore(struct mic_device *mdev) | ||
615 | { | ||
616 | int entry, offset; | ||
617 | struct pci_dev *pdev = container_of(mdev->sdev->parent, | ||
618 | struct pci_dev, dev); | ||
619 | |||
620 | if (!pci_dev_msi_enabled(pdev)) | ||
621 | return; | ||
622 | |||
623 | for (entry = 0; entry < mdev->irq_info.num_vectors; entry++) { | ||
624 | for (offset = 0; offset < MIC_NUM_OFFSETS; offset++) { | ||
625 | if (mdev->irq_info.mic_msi_map[entry] & BIT(offset)) | ||
626 | mdev->intr_ops->program_msi_to_src_map(mdev, | ||
627 | entry, offset, true); | ||
628 | } | ||
629 | } | ||
630 | } | ||
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..b3520859abd3 --- /dev/null +++ b/drivers/misc/mic/host/mic_main.c | |||
@@ -0,0 +1,537 @@ | |||
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 | #include <linux/suspend.h> | ||
30 | |||
31 | #include <linux/mic_common.h> | ||
32 | #include "../common/mic_dev.h" | ||
33 | #include "mic_device.h" | ||
34 | #include "mic_x100.h" | ||
35 | #include "mic_smpt.h" | ||
36 | #include "mic_fops.h" | ||
37 | #include "mic_virtio.h" | ||
38 | |||
39 | static const char mic_driver_name[] = "mic"; | ||
40 | |||
41 | static DEFINE_PCI_DEVICE_TABLE(mic_pci_tbl) = { | ||
42 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2250)}, | ||
43 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2251)}, | ||
44 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2252)}, | ||
45 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2253)}, | ||
46 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2254)}, | ||
47 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2255)}, | ||
48 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2256)}, | ||
49 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2257)}, | ||
50 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2258)}, | ||
51 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_2259)}, | ||
52 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225a)}, | ||
53 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225b)}, | ||
54 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225c)}, | ||
55 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225d)}, | ||
56 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, MIC_X100_PCI_DEVICE_225e)}, | ||
57 | |||
58 | /* required last entry */ | ||
59 | { 0, } | ||
60 | }; | ||
61 | |||
62 | MODULE_DEVICE_TABLE(pci, mic_pci_tbl); | ||
63 | |||
64 | /* ID allocator for MIC devices */ | ||
65 | static struct ida g_mic_ida; | ||
66 | /* Class of MIC devices for sysfs accessibility. */ | ||
67 | static struct class *g_mic_class; | ||
68 | /* Base device node number for MIC devices */ | ||
69 | static dev_t g_mic_devno; | ||
70 | |||
71 | static const struct file_operations mic_fops = { | ||
72 | .open = mic_open, | ||
73 | .release = mic_release, | ||
74 | .unlocked_ioctl = mic_ioctl, | ||
75 | .poll = mic_poll, | ||
76 | .mmap = mic_mmap, | ||
77 | .owner = THIS_MODULE, | ||
78 | }; | ||
79 | |||
80 | /* Initialize the device page */ | ||
81 | static int mic_dp_init(struct mic_device *mdev) | ||
82 | { | ||
83 | mdev->dp = kzalloc(MIC_DP_SIZE, GFP_KERNEL); | ||
84 | if (!mdev->dp) { | ||
85 | dev_err(mdev->sdev->parent, "%s %d err %d\n", | ||
86 | __func__, __LINE__, -ENOMEM); | ||
87 | return -ENOMEM; | ||
88 | } | ||
89 | |||
90 | mdev->dp_dma_addr = mic_map_single(mdev, | ||
91 | mdev->dp, MIC_DP_SIZE); | ||
92 | if (mic_map_error(mdev->dp_dma_addr)) { | ||
93 | kfree(mdev->dp); | ||
94 | dev_err(mdev->sdev->parent, "%s %d err %d\n", | ||
95 | __func__, __LINE__, -ENOMEM); | ||
96 | return -ENOMEM; | ||
97 | } | ||
98 | mdev->ops->write_spad(mdev, MIC_DPLO_SPAD, mdev->dp_dma_addr); | ||
99 | mdev->ops->write_spad(mdev, MIC_DPHI_SPAD, mdev->dp_dma_addr >> 32); | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | /* Uninitialize the device page */ | ||
104 | static void mic_dp_uninit(struct mic_device *mdev) | ||
105 | { | ||
106 | mic_unmap_single(mdev, mdev->dp_dma_addr, MIC_DP_SIZE); | ||
107 | kfree(mdev->dp); | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * mic_shutdown_db - Shutdown doorbell interrupt handler. | ||
112 | */ | ||
113 | static irqreturn_t mic_shutdown_db(int irq, void *data) | ||
114 | { | ||
115 | struct mic_device *mdev = data; | ||
116 | struct mic_bootparam *bootparam = mdev->dp; | ||
117 | |||
118 | mdev->ops->ack_interrupt(mdev); | ||
119 | |||
120 | switch (bootparam->shutdown_status) { | ||
121 | case MIC_HALTED: | ||
122 | case MIC_POWER_OFF: | ||
123 | case MIC_RESTART: | ||
124 | /* Fall through */ | ||
125 | case MIC_CRASHED: | ||
126 | schedule_work(&mdev->shutdown_work); | ||
127 | break; | ||
128 | default: | ||
129 | break; | ||
130 | }; | ||
131 | return IRQ_HANDLED; | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * mic_ops_init: Initialize HW specific operation tables. | ||
136 | * | ||
137 | * @mdev: pointer to mic_device instance | ||
138 | * | ||
139 | * returns none. | ||
140 | */ | ||
141 | static void mic_ops_init(struct mic_device *mdev) | ||
142 | { | ||
143 | switch (mdev->family) { | ||
144 | case MIC_FAMILY_X100: | ||
145 | mdev->ops = &mic_x100_ops; | ||
146 | mdev->intr_ops = &mic_x100_intr_ops; | ||
147 | mdev->smpt_ops = &mic_x100_smpt_ops; | ||
148 | break; | ||
149 | default: | ||
150 | break; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | /** | ||
155 | * mic_get_family - Determine hardware family to which this MIC belongs. | ||
156 | * | ||
157 | * @pdev: The pci device structure | ||
158 | * | ||
159 | * returns family. | ||
160 | */ | ||
161 | static enum mic_hw_family mic_get_family(struct pci_dev *pdev) | ||
162 | { | ||
163 | enum mic_hw_family family; | ||
164 | |||
165 | switch (pdev->device) { | ||
166 | case MIC_X100_PCI_DEVICE_2250: | ||
167 | case MIC_X100_PCI_DEVICE_2251: | ||
168 | case MIC_X100_PCI_DEVICE_2252: | ||
169 | case MIC_X100_PCI_DEVICE_2253: | ||
170 | case MIC_X100_PCI_DEVICE_2254: | ||
171 | case MIC_X100_PCI_DEVICE_2255: | ||
172 | case MIC_X100_PCI_DEVICE_2256: | ||
173 | case MIC_X100_PCI_DEVICE_2257: | ||
174 | case MIC_X100_PCI_DEVICE_2258: | ||
175 | case MIC_X100_PCI_DEVICE_2259: | ||
176 | case MIC_X100_PCI_DEVICE_225a: | ||
177 | case MIC_X100_PCI_DEVICE_225b: | ||
178 | case MIC_X100_PCI_DEVICE_225c: | ||
179 | case MIC_X100_PCI_DEVICE_225d: | ||
180 | case MIC_X100_PCI_DEVICE_225e: | ||
181 | family = MIC_FAMILY_X100; | ||
182 | break; | ||
183 | default: | ||
184 | family = MIC_FAMILY_UNKNOWN; | ||
185 | break; | ||
186 | } | ||
187 | return family; | ||
188 | } | ||
189 | |||
190 | /** | ||
191 | * mic_pm_notifier: Notifier callback function that handles | ||
192 | * PM notifications. | ||
193 | * | ||
194 | * @notifier_block: The notifier structure. | ||
195 | * @pm_event: The event for which the driver was notified. | ||
196 | * @unused: Meaningless. Always NULL. | ||
197 | * | ||
198 | * returns NOTIFY_DONE | ||
199 | */ | ||
200 | static int mic_pm_notifier(struct notifier_block *notifier, | ||
201 | unsigned long pm_event, void *unused) | ||
202 | { | ||
203 | struct mic_device *mdev = container_of(notifier, | ||
204 | struct mic_device, pm_notifier); | ||
205 | |||
206 | switch (pm_event) { | ||
207 | case PM_HIBERNATION_PREPARE: | ||
208 | /* Fall through */ | ||
209 | case PM_SUSPEND_PREPARE: | ||
210 | mic_prepare_suspend(mdev); | ||
211 | break; | ||
212 | case PM_POST_HIBERNATION: | ||
213 | /* Fall through */ | ||
214 | case PM_POST_SUSPEND: | ||
215 | /* Fall through */ | ||
216 | case PM_POST_RESTORE: | ||
217 | mic_complete_resume(mdev); | ||
218 | break; | ||
219 | case PM_RESTORE_PREPARE: | ||
220 | break; | ||
221 | default: | ||
222 | break; | ||
223 | } | ||
224 | return NOTIFY_DONE; | ||
225 | } | ||
226 | |||
227 | /** | ||
228 | * mic_device_init - Allocates and initializes the MIC device structure | ||
229 | * | ||
230 | * @mdev: pointer to mic_device instance | ||
231 | * @pdev: The pci device structure | ||
232 | * | ||
233 | * returns none. | ||
234 | */ | ||
235 | static int | ||
236 | mic_device_init(struct mic_device *mdev, struct pci_dev *pdev) | ||
237 | { | ||
238 | int rc; | ||
239 | |||
240 | mdev->family = mic_get_family(pdev); | ||
241 | mdev->stepping = pdev->revision; | ||
242 | mic_ops_init(mdev); | ||
243 | mic_sysfs_init(mdev); | ||
244 | mutex_init(&mdev->mic_mutex); | ||
245 | mdev->irq_info.next_avail_src = 0; | ||
246 | INIT_WORK(&mdev->reset_trigger_work, mic_reset_trigger_work); | ||
247 | INIT_WORK(&mdev->shutdown_work, mic_shutdown_work); | ||
248 | init_completion(&mdev->reset_wait); | ||
249 | INIT_LIST_HEAD(&mdev->vdev_list); | ||
250 | mdev->pm_notifier.notifier_call = mic_pm_notifier; | ||
251 | rc = register_pm_notifier(&mdev->pm_notifier); | ||
252 | if (rc) { | ||
253 | dev_err(&pdev->dev, "register_pm_notifier failed rc %d\n", | ||
254 | rc); | ||
255 | goto register_pm_notifier_fail; | ||
256 | } | ||
257 | return 0; | ||
258 | register_pm_notifier_fail: | ||
259 | flush_work(&mdev->shutdown_work); | ||
260 | flush_work(&mdev->reset_trigger_work); | ||
261 | return rc; | ||
262 | } | ||
263 | |||
264 | /** | ||
265 | * mic_device_uninit - Frees resources allocated during mic_device_init(..) | ||
266 | * | ||
267 | * @mdev: pointer to mic_device instance | ||
268 | * | ||
269 | * returns none | ||
270 | */ | ||
271 | static void mic_device_uninit(struct mic_device *mdev) | ||
272 | { | ||
273 | /* The cmdline sysfs entry might have allocated cmdline */ | ||
274 | kfree(mdev->cmdline); | ||
275 | kfree(mdev->firmware); | ||
276 | kfree(mdev->ramdisk); | ||
277 | kfree(mdev->bootmode); | ||
278 | flush_work(&mdev->reset_trigger_work); | ||
279 | flush_work(&mdev->shutdown_work); | ||
280 | unregister_pm_notifier(&mdev->pm_notifier); | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * mic_probe - Device Initialization Routine | ||
285 | * | ||
286 | * @pdev: PCI device structure | ||
287 | * @ent: entry in mic_pci_tbl | ||
288 | * | ||
289 | * returns 0 on success, < 0 on failure. | ||
290 | */ | ||
291 | static int mic_probe(struct pci_dev *pdev, | ||
292 | const struct pci_device_id *ent) | ||
293 | { | ||
294 | int rc; | ||
295 | struct mic_device *mdev; | ||
296 | |||
297 | mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); | ||
298 | if (!mdev) { | ||
299 | rc = -ENOMEM; | ||
300 | dev_err(&pdev->dev, "mdev kmalloc failed rc %d\n", rc); | ||
301 | goto mdev_alloc_fail; | ||
302 | } | ||
303 | mdev->id = ida_simple_get(&g_mic_ida, 0, MIC_MAX_NUM_DEVS, GFP_KERNEL); | ||
304 | if (mdev->id < 0) { | ||
305 | rc = mdev->id; | ||
306 | dev_err(&pdev->dev, "ida_simple_get failed rc %d\n", rc); | ||
307 | goto ida_fail; | ||
308 | } | ||
309 | |||
310 | rc = mic_device_init(mdev, pdev); | ||
311 | if (rc) { | ||
312 | dev_err(&pdev->dev, "mic_device_init failed rc %d\n", rc); | ||
313 | goto device_init_fail; | ||
314 | } | ||
315 | |||
316 | rc = pci_enable_device(pdev); | ||
317 | if (rc) { | ||
318 | dev_err(&pdev->dev, "failed to enable pci device.\n"); | ||
319 | goto uninit_device; | ||
320 | } | ||
321 | |||
322 | pci_set_master(pdev); | ||
323 | |||
324 | rc = pci_request_regions(pdev, mic_driver_name); | ||
325 | if (rc) { | ||
326 | dev_err(&pdev->dev, "failed to get pci regions.\n"); | ||
327 | goto disable_device; | ||
328 | } | ||
329 | |||
330 | rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); | ||
331 | if (rc) { | ||
332 | dev_err(&pdev->dev, "Cannot set DMA mask\n"); | ||
333 | goto release_regions; | ||
334 | } | ||
335 | |||
336 | mdev->mmio.pa = pci_resource_start(pdev, mdev->ops->mmio_bar); | ||
337 | mdev->mmio.len = pci_resource_len(pdev, mdev->ops->mmio_bar); | ||
338 | mdev->mmio.va = pci_ioremap_bar(pdev, mdev->ops->mmio_bar); | ||
339 | if (!mdev->mmio.va) { | ||
340 | dev_err(&pdev->dev, "Cannot remap MMIO BAR\n"); | ||
341 | rc = -EIO; | ||
342 | goto release_regions; | ||
343 | } | ||
344 | |||
345 | mdev->aper.pa = pci_resource_start(pdev, mdev->ops->aper_bar); | ||
346 | mdev->aper.len = pci_resource_len(pdev, mdev->ops->aper_bar); | ||
347 | mdev->aper.va = ioremap_wc(mdev->aper.pa, mdev->aper.len); | ||
348 | if (!mdev->aper.va) { | ||
349 | dev_err(&pdev->dev, "Cannot remap Aperture BAR\n"); | ||
350 | rc = -EIO; | ||
351 | goto unmap_mmio; | ||
352 | } | ||
353 | |||
354 | mdev->intr_ops->intr_init(mdev); | ||
355 | rc = mic_setup_interrupts(mdev, pdev); | ||
356 | if (rc) { | ||
357 | dev_err(&pdev->dev, "mic_setup_interrupts failed %d\n", rc); | ||
358 | goto unmap_aper; | ||
359 | } | ||
360 | rc = mic_smpt_init(mdev); | ||
361 | if (rc) { | ||
362 | dev_err(&pdev->dev, "smpt_init failed %d\n", rc); | ||
363 | goto free_interrupts; | ||
364 | } | ||
365 | |||
366 | pci_set_drvdata(pdev, mdev); | ||
367 | |||
368 | mdev->sdev = device_create_with_groups(g_mic_class, &pdev->dev, | ||
369 | MKDEV(MAJOR(g_mic_devno), mdev->id), NULL, | ||
370 | mdev->attr_group, "mic%d", mdev->id); | ||
371 | if (IS_ERR(mdev->sdev)) { | ||
372 | rc = PTR_ERR(mdev->sdev); | ||
373 | dev_err(&pdev->dev, | ||
374 | "device_create_with_groups failed rc %d\n", rc); | ||
375 | goto smpt_uninit; | ||
376 | } | ||
377 | mdev->state_sysfs = sysfs_get_dirent(mdev->sdev->kobj.sd, | ||
378 | NULL, "state"); | ||
379 | if (!mdev->state_sysfs) { | ||
380 | rc = -ENODEV; | ||
381 | dev_err(&pdev->dev, "sysfs_get_dirent failed rc %d\n", rc); | ||
382 | goto destroy_device; | ||
383 | } | ||
384 | |||
385 | rc = mic_dp_init(mdev); | ||
386 | if (rc) { | ||
387 | dev_err(&pdev->dev, "mic_dp_init failed rc %d\n", rc); | ||
388 | goto sysfs_put; | ||
389 | } | ||
390 | mutex_lock(&mdev->mic_mutex); | ||
391 | |||
392 | mdev->shutdown_db = mic_next_db(mdev); | ||
393 | mdev->shutdown_cookie = mic_request_irq(mdev, mic_shutdown_db, | ||
394 | "shutdown-interrupt", mdev, mdev->shutdown_db, MIC_INTR_DB); | ||
395 | if (IS_ERR(mdev->shutdown_cookie)) { | ||
396 | rc = PTR_ERR(mdev->shutdown_cookie); | ||
397 | mutex_unlock(&mdev->mic_mutex); | ||
398 | goto dp_uninit; | ||
399 | } | ||
400 | mutex_unlock(&mdev->mic_mutex); | ||
401 | mic_bootparam_init(mdev); | ||
402 | |||
403 | mic_create_debug_dir(mdev); | ||
404 | cdev_init(&mdev->cdev, &mic_fops); | ||
405 | mdev->cdev.owner = THIS_MODULE; | ||
406 | rc = cdev_add(&mdev->cdev, MKDEV(MAJOR(g_mic_devno), mdev->id), 1); | ||
407 | if (rc) { | ||
408 | dev_err(&pdev->dev, "cdev_add err id %d rc %d\n", mdev->id, rc); | ||
409 | goto cleanup_debug_dir; | ||
410 | } | ||
411 | return 0; | ||
412 | cleanup_debug_dir: | ||
413 | mic_delete_debug_dir(mdev); | ||
414 | mutex_lock(&mdev->mic_mutex); | ||
415 | mic_free_irq(mdev, mdev->shutdown_cookie, mdev); | ||
416 | mutex_unlock(&mdev->mic_mutex); | ||
417 | dp_uninit: | ||
418 | mic_dp_uninit(mdev); | ||
419 | sysfs_put: | ||
420 | sysfs_put(mdev->state_sysfs); | ||
421 | destroy_device: | ||
422 | device_destroy(g_mic_class, MKDEV(MAJOR(g_mic_devno), mdev->id)); | ||
423 | smpt_uninit: | ||
424 | mic_smpt_uninit(mdev); | ||
425 | free_interrupts: | ||
426 | mic_free_interrupts(mdev, pdev); | ||
427 | unmap_aper: | ||
428 | iounmap(mdev->aper.va); | ||
429 | unmap_mmio: | ||
430 | iounmap(mdev->mmio.va); | ||
431 | release_regions: | ||
432 | pci_release_regions(pdev); | ||
433 | disable_device: | ||
434 | pci_disable_device(pdev); | ||
435 | uninit_device: | ||
436 | mic_device_uninit(mdev); | ||
437 | device_init_fail: | ||
438 | ida_simple_remove(&g_mic_ida, mdev->id); | ||
439 | ida_fail: | ||
440 | kfree(mdev); | ||
441 | mdev_alloc_fail: | ||
442 | dev_err(&pdev->dev, "Probe failed rc %d\n", rc); | ||
443 | return rc; | ||
444 | } | ||
445 | |||
446 | /** | ||
447 | * mic_remove - Device Removal Routine | ||
448 | * mic_remove is called by the PCI subsystem to alert the driver | ||
449 | * that it should release a PCI device. | ||
450 | * | ||
451 | * @pdev: PCI device structure | ||
452 | */ | ||
453 | static void mic_remove(struct pci_dev *pdev) | ||
454 | { | ||
455 | struct mic_device *mdev; | ||
456 | |||
457 | mdev = pci_get_drvdata(pdev); | ||
458 | if (!mdev) | ||
459 | return; | ||
460 | |||
461 | mic_stop(mdev, false); | ||
462 | cdev_del(&mdev->cdev); | ||
463 | mic_delete_debug_dir(mdev); | ||
464 | mutex_lock(&mdev->mic_mutex); | ||
465 | mic_free_irq(mdev, mdev->shutdown_cookie, mdev); | ||
466 | mutex_unlock(&mdev->mic_mutex); | ||
467 | flush_work(&mdev->shutdown_work); | ||
468 | mic_dp_uninit(mdev); | ||
469 | sysfs_put(mdev->state_sysfs); | ||
470 | device_destroy(g_mic_class, MKDEV(MAJOR(g_mic_devno), mdev->id)); | ||
471 | mic_smpt_uninit(mdev); | ||
472 | mic_free_interrupts(mdev, pdev); | ||
473 | iounmap(mdev->mmio.va); | ||
474 | iounmap(mdev->aper.va); | ||
475 | mic_device_uninit(mdev); | ||
476 | pci_release_regions(pdev); | ||
477 | pci_disable_device(pdev); | ||
478 | ida_simple_remove(&g_mic_ida, mdev->id); | ||
479 | kfree(mdev); | ||
480 | } | ||
481 | static struct pci_driver mic_driver = { | ||
482 | .name = mic_driver_name, | ||
483 | .id_table = mic_pci_tbl, | ||
484 | .probe = mic_probe, | ||
485 | .remove = mic_remove | ||
486 | }; | ||
487 | |||
488 | static int __init mic_init(void) | ||
489 | { | ||
490 | int ret; | ||
491 | |||
492 | ret = alloc_chrdev_region(&g_mic_devno, 0, | ||
493 | MIC_MAX_NUM_DEVS, mic_driver_name); | ||
494 | if (ret) { | ||
495 | pr_err("alloc_chrdev_region failed ret %d\n", ret); | ||
496 | goto error; | ||
497 | } | ||
498 | |||
499 | g_mic_class = class_create(THIS_MODULE, mic_driver_name); | ||
500 | if (IS_ERR(g_mic_class)) { | ||
501 | ret = PTR_ERR(g_mic_class); | ||
502 | pr_err("class_create failed ret %d\n", ret); | ||
503 | goto cleanup_chrdev; | ||
504 | } | ||
505 | |||
506 | mic_init_debugfs(); | ||
507 | ida_init(&g_mic_ida); | ||
508 | ret = pci_register_driver(&mic_driver); | ||
509 | if (ret) { | ||
510 | pr_err("pci_register_driver failed ret %d\n", ret); | ||
511 | goto cleanup_debugfs; | ||
512 | } | ||
513 | return ret; | ||
514 | cleanup_debugfs: | ||
515 | mic_exit_debugfs(); | ||
516 | class_destroy(g_mic_class); | ||
517 | cleanup_chrdev: | ||
518 | unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS); | ||
519 | error: | ||
520 | return ret; | ||
521 | } | ||
522 | |||
523 | static void __exit mic_exit(void) | ||
524 | { | ||
525 | pci_unregister_driver(&mic_driver); | ||
526 | ida_destroy(&g_mic_ida); | ||
527 | mic_exit_debugfs(); | ||
528 | class_destroy(g_mic_class); | ||
529 | unregister_chrdev_region(g_mic_devno, MIC_MAX_NUM_DEVS); | ||
530 | } | ||
531 | |||
532 | module_init(mic_init); | ||
533 | module_exit(mic_exit); | ||
534 | |||
535 | MODULE_AUTHOR("Intel Corporation"); | ||
536 | MODULE_DESCRIPTION("Intel(R) MIC X100 Host driver"); | ||
537 | 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..fae474c4899e --- /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_dev.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_array(smpt_info->info.num_reg, | ||
370 | sizeof(*smpt_info->entry), 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..6dd864e4a617 --- /dev/null +++ b/drivers/misc/mic/host/mic_sysfs.c | |||
@@ -0,0 +1,459 @@ | |||
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_dev.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 | [MIC_SUSPENDING] = "suspending", | ||
37 | [MIC_SUSPENDED] = "suspended", | ||
38 | }; | ||
39 | |||
40 | /* | ||
41 | * A shutdown-status-to-string lookup table, for exposing a human | ||
42 | * readable state via sysfs. Always keep in sync with enum mic_shutdown_status | ||
43 | */ | ||
44 | static const char * const mic_shutdown_status_string[] = { | ||
45 | [MIC_NOP] = "nop", | ||
46 | [MIC_CRASHED] = "crashed", | ||
47 | [MIC_HALTED] = "halted", | ||
48 | [MIC_POWER_OFF] = "poweroff", | ||
49 | [MIC_RESTART] = "restart", | ||
50 | }; | ||
51 | |||
52 | void mic_set_shutdown_status(struct mic_device *mdev, u8 shutdown_status) | ||
53 | { | ||
54 | dev_dbg(mdev->sdev->parent, "Shutdown Status %s -> %s\n", | ||
55 | mic_shutdown_status_string[mdev->shutdown_status], | ||
56 | mic_shutdown_status_string[shutdown_status]); | ||
57 | mdev->shutdown_status = shutdown_status; | ||
58 | } | ||
59 | |||
60 | void mic_set_state(struct mic_device *mdev, u8 state) | ||
61 | { | ||
62 | dev_dbg(mdev->sdev->parent, "State %s -> %s\n", | ||
63 | mic_state_string[mdev->state], | ||
64 | mic_state_string[state]); | ||
65 | mdev->state = state; | ||
66 | sysfs_notify_dirent(mdev->state_sysfs); | ||
67 | } | ||
68 | |||
69 | static ssize_t | ||
70 | family_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
71 | { | ||
72 | static const char x100[] = "x100"; | ||
73 | static const char unknown[] = "Unknown"; | ||
74 | const char *card = NULL; | ||
75 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
76 | |||
77 | if (!mdev) | ||
78 | return -EINVAL; | ||
79 | |||
80 | switch (mdev->family) { | ||
81 | case MIC_FAMILY_X100: | ||
82 | card = x100; | ||
83 | break; | ||
84 | default: | ||
85 | card = unknown; | ||
86 | break; | ||
87 | } | ||
88 | return scnprintf(buf, PAGE_SIZE, "%s\n", card); | ||
89 | } | ||
90 | static DEVICE_ATTR_RO(family); | ||
91 | |||
92 | static ssize_t | ||
93 | stepping_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
94 | { | ||
95 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
96 | char *string = "??"; | ||
97 | |||
98 | if (!mdev) | ||
99 | return -EINVAL; | ||
100 | |||
101 | switch (mdev->stepping) { | ||
102 | case MIC_A0_STEP: | ||
103 | string = "A0"; | ||
104 | break; | ||
105 | case MIC_B0_STEP: | ||
106 | string = "B0"; | ||
107 | break; | ||
108 | case MIC_B1_STEP: | ||
109 | string = "B1"; | ||
110 | break; | ||
111 | case MIC_C0_STEP: | ||
112 | string = "C0"; | ||
113 | break; | ||
114 | default: | ||
115 | break; | ||
116 | } | ||
117 | return scnprintf(buf, PAGE_SIZE, "%s\n", string); | ||
118 | } | ||
119 | static DEVICE_ATTR_RO(stepping); | ||
120 | |||
121 | static ssize_t | ||
122 | state_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
123 | { | ||
124 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
125 | |||
126 | if (!mdev || mdev->state >= MIC_LAST) | ||
127 | return -EINVAL; | ||
128 | |||
129 | return scnprintf(buf, PAGE_SIZE, "%s\n", | ||
130 | mic_state_string[mdev->state]); | ||
131 | } | ||
132 | |||
133 | static ssize_t | ||
134 | state_store(struct device *dev, struct device_attribute *attr, | ||
135 | const char *buf, size_t count) | ||
136 | { | ||
137 | int rc = 0; | ||
138 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
139 | if (!mdev) | ||
140 | return -EINVAL; | ||
141 | if (sysfs_streq(buf, "boot")) { | ||
142 | rc = mic_start(mdev, buf); | ||
143 | if (rc) { | ||
144 | dev_err(mdev->sdev->parent, | ||
145 | "mic_boot failed rc %d\n", rc); | ||
146 | count = rc; | ||
147 | } | ||
148 | goto done; | ||
149 | } | ||
150 | |||
151 | if (sysfs_streq(buf, "reset")) { | ||
152 | schedule_work(&mdev->reset_trigger_work); | ||
153 | goto done; | ||
154 | } | ||
155 | |||
156 | if (sysfs_streq(buf, "shutdown")) { | ||
157 | mic_shutdown(mdev); | ||
158 | goto done; | ||
159 | } | ||
160 | |||
161 | if (sysfs_streq(buf, "suspend")) { | ||
162 | mic_suspend(mdev); | ||
163 | goto done; | ||
164 | } | ||
165 | |||
166 | count = -EINVAL; | ||
167 | done: | ||
168 | return count; | ||
169 | } | ||
170 | static DEVICE_ATTR_RW(state); | ||
171 | |||
172 | static ssize_t shutdown_status_show(struct device *dev, | ||
173 | struct device_attribute *attr, char *buf) | ||
174 | { | ||
175 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
176 | |||
177 | if (!mdev || mdev->shutdown_status >= MIC_STATUS_LAST) | ||
178 | return -EINVAL; | ||
179 | |||
180 | return scnprintf(buf, PAGE_SIZE, "%s\n", | ||
181 | mic_shutdown_status_string[mdev->shutdown_status]); | ||
182 | } | ||
183 | static DEVICE_ATTR_RO(shutdown_status); | ||
184 | |||
185 | static ssize_t | ||
186 | cmdline_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
187 | { | ||
188 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
189 | char *cmdline; | ||
190 | |||
191 | if (!mdev) | ||
192 | return -EINVAL; | ||
193 | |||
194 | cmdline = mdev->cmdline; | ||
195 | |||
196 | if (cmdline) | ||
197 | return scnprintf(buf, PAGE_SIZE, "%s\n", cmdline); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static ssize_t | ||
202 | cmdline_store(struct device *dev, struct device_attribute *attr, | ||
203 | const char *buf, size_t count) | ||
204 | { | ||
205 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
206 | |||
207 | if (!mdev) | ||
208 | return -EINVAL; | ||
209 | |||
210 | mutex_lock(&mdev->mic_mutex); | ||
211 | kfree(mdev->cmdline); | ||
212 | |||
213 | mdev->cmdline = kmalloc(count + 1, GFP_KERNEL); | ||
214 | if (!mdev->cmdline) { | ||
215 | count = -ENOMEM; | ||
216 | goto unlock; | ||
217 | } | ||
218 | |||
219 | strncpy(mdev->cmdline, buf, count); | ||
220 | |||
221 | if (mdev->cmdline[count - 1] == '\n') | ||
222 | mdev->cmdline[count - 1] = '\0'; | ||
223 | else | ||
224 | mdev->cmdline[count] = '\0'; | ||
225 | unlock: | ||
226 | mutex_unlock(&mdev->mic_mutex); | ||
227 | return count; | ||
228 | } | ||
229 | static DEVICE_ATTR_RW(cmdline); | ||
230 | |||
231 | static ssize_t | ||
232 | firmware_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
233 | { | ||
234 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
235 | char *firmware; | ||
236 | |||
237 | if (!mdev) | ||
238 | return -EINVAL; | ||
239 | |||
240 | firmware = mdev->firmware; | ||
241 | |||
242 | if (firmware) | ||
243 | return scnprintf(buf, PAGE_SIZE, "%s\n", firmware); | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static ssize_t | ||
248 | firmware_store(struct device *dev, struct device_attribute *attr, | ||
249 | const char *buf, size_t count) | ||
250 | { | ||
251 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
252 | |||
253 | if (!mdev) | ||
254 | return -EINVAL; | ||
255 | |||
256 | mutex_lock(&mdev->mic_mutex); | ||
257 | kfree(mdev->firmware); | ||
258 | |||
259 | mdev->firmware = kmalloc(count + 1, GFP_KERNEL); | ||
260 | if (!mdev->firmware) { | ||
261 | count = -ENOMEM; | ||
262 | goto unlock; | ||
263 | } | ||
264 | strncpy(mdev->firmware, buf, count); | ||
265 | |||
266 | if (mdev->firmware[count - 1] == '\n') | ||
267 | mdev->firmware[count - 1] = '\0'; | ||
268 | else | ||
269 | mdev->firmware[count] = '\0'; | ||
270 | unlock: | ||
271 | mutex_unlock(&mdev->mic_mutex); | ||
272 | return count; | ||
273 | } | ||
274 | static DEVICE_ATTR_RW(firmware); | ||
275 | |||
276 | static ssize_t | ||
277 | ramdisk_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
278 | { | ||
279 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
280 | char *ramdisk; | ||
281 | |||
282 | if (!mdev) | ||
283 | return -EINVAL; | ||
284 | |||
285 | ramdisk = mdev->ramdisk; | ||
286 | |||
287 | if (ramdisk) | ||
288 | return scnprintf(buf, PAGE_SIZE, "%s\n", ramdisk); | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static ssize_t | ||
293 | ramdisk_store(struct device *dev, struct device_attribute *attr, | ||
294 | const char *buf, size_t count) | ||
295 | { | ||
296 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
297 | |||
298 | if (!mdev) | ||
299 | return -EINVAL; | ||
300 | |||
301 | mutex_lock(&mdev->mic_mutex); | ||
302 | kfree(mdev->ramdisk); | ||
303 | |||
304 | mdev->ramdisk = kmalloc(count + 1, GFP_KERNEL); | ||
305 | if (!mdev->ramdisk) { | ||
306 | count = -ENOMEM; | ||
307 | goto unlock; | ||
308 | } | ||
309 | |||
310 | strncpy(mdev->ramdisk, buf, count); | ||
311 | |||
312 | if (mdev->ramdisk[count - 1] == '\n') | ||
313 | mdev->ramdisk[count - 1] = '\0'; | ||
314 | else | ||
315 | mdev->ramdisk[count] = '\0'; | ||
316 | unlock: | ||
317 | mutex_unlock(&mdev->mic_mutex); | ||
318 | return count; | ||
319 | } | ||
320 | static DEVICE_ATTR_RW(ramdisk); | ||
321 | |||
322 | static ssize_t | ||
323 | bootmode_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
324 | { | ||
325 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
326 | char *bootmode; | ||
327 | |||
328 | if (!mdev) | ||
329 | return -EINVAL; | ||
330 | |||
331 | bootmode = mdev->bootmode; | ||
332 | |||
333 | if (bootmode) | ||
334 | return scnprintf(buf, PAGE_SIZE, "%s\n", bootmode); | ||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static ssize_t | ||
339 | bootmode_store(struct device *dev, struct device_attribute *attr, | ||
340 | const char *buf, size_t count) | ||
341 | { | ||
342 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
343 | |||
344 | if (!mdev) | ||
345 | return -EINVAL; | ||
346 | |||
347 | if (!sysfs_streq(buf, "linux") && !sysfs_streq(buf, "elf")) | ||
348 | return -EINVAL; | ||
349 | |||
350 | mutex_lock(&mdev->mic_mutex); | ||
351 | kfree(mdev->bootmode); | ||
352 | |||
353 | mdev->bootmode = kmalloc(count + 1, GFP_KERNEL); | ||
354 | if (!mdev->bootmode) { | ||
355 | count = -ENOMEM; | ||
356 | goto unlock; | ||
357 | } | ||
358 | |||
359 | strncpy(mdev->bootmode, buf, count); | ||
360 | |||
361 | if (mdev->bootmode[count - 1] == '\n') | ||
362 | mdev->bootmode[count - 1] = '\0'; | ||
363 | else | ||
364 | mdev->bootmode[count] = '\0'; | ||
365 | unlock: | ||
366 | mutex_unlock(&mdev->mic_mutex); | ||
367 | return count; | ||
368 | } | ||
369 | static DEVICE_ATTR_RW(bootmode); | ||
370 | |||
371 | static ssize_t | ||
372 | log_buf_addr_show(struct device *dev, struct device_attribute *attr, | ||
373 | char *buf) | ||
374 | { | ||
375 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
376 | |||
377 | if (!mdev) | ||
378 | return -EINVAL; | ||
379 | |||
380 | return scnprintf(buf, PAGE_SIZE, "%p\n", mdev->log_buf_addr); | ||
381 | } | ||
382 | |||
383 | static ssize_t | ||
384 | log_buf_addr_store(struct device *dev, struct device_attribute *attr, | ||
385 | const char *buf, size_t count) | ||
386 | { | ||
387 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
388 | int ret; | ||
389 | unsigned long addr; | ||
390 | |||
391 | if (!mdev) | ||
392 | return -EINVAL; | ||
393 | |||
394 | ret = kstrtoul(buf, 16, &addr); | ||
395 | if (ret) | ||
396 | goto exit; | ||
397 | |||
398 | mdev->log_buf_addr = (void *)addr; | ||
399 | ret = count; | ||
400 | exit: | ||
401 | return ret; | ||
402 | } | ||
403 | static DEVICE_ATTR_RW(log_buf_addr); | ||
404 | |||
405 | static ssize_t | ||
406 | log_buf_len_show(struct device *dev, struct device_attribute *attr, | ||
407 | char *buf) | ||
408 | { | ||
409 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
410 | |||
411 | if (!mdev) | ||
412 | return -EINVAL; | ||
413 | |||
414 | return scnprintf(buf, PAGE_SIZE, "%p\n", mdev->log_buf_len); | ||
415 | } | ||
416 | |||
417 | static ssize_t | ||
418 | log_buf_len_store(struct device *dev, struct device_attribute *attr, | ||
419 | const char *buf, size_t count) | ||
420 | { | ||
421 | struct mic_device *mdev = dev_get_drvdata(dev->parent); | ||
422 | int ret; | ||
423 | unsigned long addr; | ||
424 | |||
425 | if (!mdev) | ||
426 | return -EINVAL; | ||
427 | |||
428 | ret = kstrtoul(buf, 16, &addr); | ||
429 | if (ret) | ||
430 | goto exit; | ||
431 | |||
432 | mdev->log_buf_len = (int *)addr; | ||
433 | ret = count; | ||
434 | exit: | ||
435 | return ret; | ||
436 | } | ||
437 | static DEVICE_ATTR_RW(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 | ATTRIBUTE_GROUPS(mic_default); | ||
455 | |||
456 | void mic_sysfs_init(struct mic_device *mdev) | ||
457 | { | ||
458 | mdev->attr_group = mic_default_groups; | ||
459 | } | ||
diff --git a/drivers/misc/mic/host/mic_virtio.c b/drivers/misc/mic/host/mic_virtio.c new file mode 100644 index 000000000000..5b8494bd1e00 --- /dev/null +++ b/drivers/misc/mic/host/mic_virtio.c | |||
@@ -0,0 +1,700 @@ | |||
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_dev.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 && copy->update_used) { | ||
229 | u32 total = 0; | ||
230 | |||
231 | /* Determine the total data consumed */ | ||
232 | total += mic_vringh_iov_consumed(riov); | ||
233 | total += mic_vringh_iov_consumed(wiov); | ||
234 | vringh_complete_kern(vrh, *head, total); | ||
235 | *head = USHRT_MAX; | ||
236 | if (vringh_need_notify_kern(vrh) > 0) | ||
237 | vringh_notify(vrh); | ||
238 | vringh_kiov_cleanup(riov); | ||
239 | vringh_kiov_cleanup(wiov); | ||
240 | /* Update avail idx for user space */ | ||
241 | vr->info->avail_idx = vrh->last_avail_idx; | ||
242 | } | ||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | static inline int mic_verify_copy_args(struct mic_vdev *mvdev, | ||
247 | struct mic_copy_desc *copy) | ||
248 | { | ||
249 | if (copy->vr_idx >= mvdev->dd->num_vq) { | ||
250 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
251 | __func__, __LINE__, -EINVAL); | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | /* Copy a specified number of virtio descriptors in a chain */ | ||
258 | int mic_virtio_copy_desc(struct mic_vdev *mvdev, | ||
259 | struct mic_copy_desc *copy) | ||
260 | { | ||
261 | int err; | ||
262 | struct mic_vringh *mvr = &mvdev->mvr[copy->vr_idx]; | ||
263 | |||
264 | err = mic_verify_copy_args(mvdev, copy); | ||
265 | if (err) | ||
266 | return err; | ||
267 | |||
268 | mutex_lock(&mvr->vr_mutex); | ||
269 | if (!mic_vdevup(mvdev)) { | ||
270 | err = -ENODEV; | ||
271 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
272 | __func__, __LINE__, err); | ||
273 | goto err; | ||
274 | } | ||
275 | err = _mic_virtio_copy(mvdev, copy); | ||
276 | if (err) { | ||
277 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
278 | __func__, __LINE__, err); | ||
279 | } | ||
280 | err: | ||
281 | mutex_unlock(&mvr->vr_mutex); | ||
282 | return err; | ||
283 | } | ||
284 | |||
285 | static void mic_virtio_init_post(struct mic_vdev *mvdev) | ||
286 | { | ||
287 | struct mic_vqconfig *vqconfig = mic_vq_config(mvdev->dd); | ||
288 | int i; | ||
289 | |||
290 | for (i = 0; i < mvdev->dd->num_vq; i++) { | ||
291 | if (!le64_to_cpu(vqconfig[i].used_address)) { | ||
292 | dev_warn(mic_dev(mvdev), "used_address zero??\n"); | ||
293 | continue; | ||
294 | } | ||
295 | mvdev->mvr[i].vrh.vring.used = | ||
296 | mvdev->mdev->aper.va + | ||
297 | le64_to_cpu(vqconfig[i].used_address); | ||
298 | } | ||
299 | |||
300 | mvdev->dc->used_address_updated = 0; | ||
301 | |||
302 | dev_dbg(mic_dev(mvdev), "%s: device type %d LINKUP\n", | ||
303 | __func__, mvdev->virtio_id); | ||
304 | } | ||
305 | |||
306 | static inline void mic_virtio_device_reset(struct mic_vdev *mvdev) | ||
307 | { | ||
308 | int i; | ||
309 | |||
310 | dev_dbg(mic_dev(mvdev), "%s: status %d device type %d RESET\n", | ||
311 | __func__, mvdev->dd->status, mvdev->virtio_id); | ||
312 | |||
313 | for (i = 0; i < mvdev->dd->num_vq; i++) | ||
314 | /* | ||
315 | * Avoid lockdep false positive. The + 1 is for the mic | ||
316 | * mutex which is held in the reset devices code path. | ||
317 | */ | ||
318 | mutex_lock_nested(&mvdev->mvr[i].vr_mutex, i + 1); | ||
319 | |||
320 | /* 0 status means "reset" */ | ||
321 | mvdev->dd->status = 0; | ||
322 | mvdev->dc->vdev_reset = 0; | ||
323 | mvdev->dc->host_ack = 1; | ||
324 | |||
325 | for (i = 0; i < mvdev->dd->num_vq; i++) { | ||
326 | struct vringh *vrh = &mvdev->mvr[i].vrh; | ||
327 | mvdev->mvr[i].vring.info->avail_idx = 0; | ||
328 | vrh->completed = 0; | ||
329 | vrh->last_avail_idx = 0; | ||
330 | vrh->last_used_idx = 0; | ||
331 | } | ||
332 | |||
333 | for (i = 0; i < mvdev->dd->num_vq; i++) | ||
334 | mutex_unlock(&mvdev->mvr[i].vr_mutex); | ||
335 | } | ||
336 | |||
337 | void mic_virtio_reset_devices(struct mic_device *mdev) | ||
338 | { | ||
339 | struct list_head *pos, *tmp; | ||
340 | struct mic_vdev *mvdev; | ||
341 | |||
342 | dev_dbg(mdev->sdev->parent, "%s\n", __func__); | ||
343 | |||
344 | list_for_each_safe(pos, tmp, &mdev->vdev_list) { | ||
345 | mvdev = list_entry(pos, struct mic_vdev, list); | ||
346 | mic_virtio_device_reset(mvdev); | ||
347 | mvdev->poll_wake = 1; | ||
348 | wake_up(&mvdev->waitq); | ||
349 | } | ||
350 | } | ||
351 | |||
352 | void mic_bh_handler(struct work_struct *work) | ||
353 | { | ||
354 | struct mic_vdev *mvdev = container_of(work, struct mic_vdev, | ||
355 | virtio_bh_work); | ||
356 | |||
357 | if (mvdev->dc->used_address_updated) | ||
358 | mic_virtio_init_post(mvdev); | ||
359 | |||
360 | if (mvdev->dc->vdev_reset) | ||
361 | mic_virtio_device_reset(mvdev); | ||
362 | |||
363 | mvdev->poll_wake = 1; | ||
364 | wake_up(&mvdev->waitq); | ||
365 | } | ||
366 | |||
367 | static irqreturn_t mic_virtio_intr_handler(int irq, void *data) | ||
368 | { | ||
369 | struct mic_vdev *mvdev = data; | ||
370 | struct mic_device *mdev = mvdev->mdev; | ||
371 | |||
372 | mdev->ops->ack_interrupt(mdev); | ||
373 | schedule_work(&mvdev->virtio_bh_work); | ||
374 | return IRQ_HANDLED; | ||
375 | } | ||
376 | |||
377 | int mic_virtio_config_change(struct mic_vdev *mvdev, | ||
378 | void __user *argp) | ||
379 | { | ||
380 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake); | ||
381 | int ret = 0, retry = 100, i; | ||
382 | struct mic_bootparam *bootparam = mvdev->mdev->dp; | ||
383 | s8 db = bootparam->h2c_config_db; | ||
384 | |||
385 | mutex_lock(&mvdev->mdev->mic_mutex); | ||
386 | for (i = 0; i < mvdev->dd->num_vq; i++) | ||
387 | mutex_lock_nested(&mvdev->mvr[i].vr_mutex, i + 1); | ||
388 | |||
389 | if (db == -1 || mvdev->dd->type == -1) { | ||
390 | ret = -EIO; | ||
391 | goto exit; | ||
392 | } | ||
393 | |||
394 | if (copy_from_user(mic_vq_configspace(mvdev->dd), | ||
395 | argp, mvdev->dd->config_len)) { | ||
396 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
397 | __func__, __LINE__, -EFAULT); | ||
398 | ret = -EFAULT; | ||
399 | goto exit; | ||
400 | } | ||
401 | mvdev->dc->config_change = MIC_VIRTIO_PARAM_CONFIG_CHANGED; | ||
402 | mvdev->mdev->ops->send_intr(mvdev->mdev, db); | ||
403 | |||
404 | for (i = retry; i--;) { | ||
405 | ret = wait_event_timeout(wake, | ||
406 | mvdev->dc->guest_ack, msecs_to_jiffies(100)); | ||
407 | if (ret) | ||
408 | break; | ||
409 | } | ||
410 | |||
411 | dev_dbg(mic_dev(mvdev), | ||
412 | "%s %d retry: %d\n", __func__, __LINE__, retry); | ||
413 | mvdev->dc->config_change = 0; | ||
414 | mvdev->dc->guest_ack = 0; | ||
415 | exit: | ||
416 | for (i = 0; i < mvdev->dd->num_vq; i++) | ||
417 | mutex_unlock(&mvdev->mvr[i].vr_mutex); | ||
418 | mutex_unlock(&mvdev->mdev->mic_mutex); | ||
419 | return ret; | ||
420 | } | ||
421 | |||
422 | static int mic_copy_dp_entry(struct mic_vdev *mvdev, | ||
423 | void __user *argp, | ||
424 | __u8 *type, | ||
425 | struct mic_device_desc **devpage) | ||
426 | { | ||
427 | struct mic_device *mdev = mvdev->mdev; | ||
428 | struct mic_device_desc dd, *dd_config, *devp; | ||
429 | struct mic_vqconfig *vqconfig; | ||
430 | int ret = 0, i; | ||
431 | bool slot_found = false; | ||
432 | |||
433 | if (copy_from_user(&dd, argp, sizeof(dd))) { | ||
434 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
435 | __func__, __LINE__, -EFAULT); | ||
436 | return -EFAULT; | ||
437 | } | ||
438 | |||
439 | if (mic_aligned_desc_size(&dd) > MIC_MAX_DESC_BLK_SIZE || | ||
440 | dd.num_vq > MIC_MAX_VRINGS) { | ||
441 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
442 | __func__, __LINE__, -EINVAL); | ||
443 | return -EINVAL; | ||
444 | } | ||
445 | |||
446 | dd_config = kmalloc(mic_desc_size(&dd), GFP_KERNEL); | ||
447 | if (dd_config == NULL) { | ||
448 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
449 | __func__, __LINE__, -ENOMEM); | ||
450 | return -ENOMEM; | ||
451 | } | ||
452 | if (copy_from_user(dd_config, argp, mic_desc_size(&dd))) { | ||
453 | ret = -EFAULT; | ||
454 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
455 | __func__, __LINE__, ret); | ||
456 | goto exit; | ||
457 | } | ||
458 | |||
459 | vqconfig = mic_vq_config(dd_config); | ||
460 | for (i = 0; i < dd.num_vq; i++) { | ||
461 | if (le16_to_cpu(vqconfig[i].num) > MIC_MAX_VRING_ENTRIES) { | ||
462 | ret = -EINVAL; | ||
463 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
464 | __func__, __LINE__, ret); | ||
465 | goto exit; | ||
466 | } | ||
467 | } | ||
468 | |||
469 | /* Find the first free device page entry */ | ||
470 | for (i = mic_aligned_size(struct mic_bootparam); | ||
471 | i < MIC_DP_SIZE - mic_total_desc_size(dd_config); | ||
472 | i += mic_total_desc_size(devp)) { | ||
473 | devp = mdev->dp + i; | ||
474 | if (devp->type == 0 || devp->type == -1) { | ||
475 | slot_found = true; | ||
476 | break; | ||
477 | } | ||
478 | } | ||
479 | if (!slot_found) { | ||
480 | ret = -EINVAL; | ||
481 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
482 | __func__, __LINE__, ret); | ||
483 | goto exit; | ||
484 | } | ||
485 | /* | ||
486 | * Save off the type before doing the memcpy. Type will be set in the | ||
487 | * end after completing all initialization for the new device. | ||
488 | */ | ||
489 | *type = dd_config->type; | ||
490 | dd_config->type = 0; | ||
491 | memcpy(devp, dd_config, mic_desc_size(dd_config)); | ||
492 | |||
493 | *devpage = devp; | ||
494 | exit: | ||
495 | kfree(dd_config); | ||
496 | return ret; | ||
497 | } | ||
498 | |||
499 | static void mic_init_device_ctrl(struct mic_vdev *mvdev, | ||
500 | struct mic_device_desc *devpage) | ||
501 | { | ||
502 | struct mic_device_ctrl *dc; | ||
503 | |||
504 | dc = (void *)devpage + mic_aligned_desc_size(devpage); | ||
505 | |||
506 | dc->config_change = 0; | ||
507 | dc->guest_ack = 0; | ||
508 | dc->vdev_reset = 0; | ||
509 | dc->host_ack = 0; | ||
510 | dc->used_address_updated = 0; | ||
511 | dc->c2h_vdev_db = -1; | ||
512 | dc->h2c_vdev_db = -1; | ||
513 | mvdev->dc = dc; | ||
514 | } | ||
515 | |||
516 | int mic_virtio_add_device(struct mic_vdev *mvdev, | ||
517 | void __user *argp) | ||
518 | { | ||
519 | struct mic_device *mdev = mvdev->mdev; | ||
520 | struct mic_device_desc *dd = NULL; | ||
521 | struct mic_vqconfig *vqconfig; | ||
522 | int vr_size, i, j, ret; | ||
523 | u8 type = 0; | ||
524 | s8 db; | ||
525 | char irqname[10]; | ||
526 | struct mic_bootparam *bootparam = mdev->dp; | ||
527 | u16 num; | ||
528 | |||
529 | mutex_lock(&mdev->mic_mutex); | ||
530 | |||
531 | ret = mic_copy_dp_entry(mvdev, argp, &type, &dd); | ||
532 | if (ret) { | ||
533 | mutex_unlock(&mdev->mic_mutex); | ||
534 | return ret; | ||
535 | } | ||
536 | |||
537 | mic_init_device_ctrl(mvdev, dd); | ||
538 | |||
539 | mvdev->dd = dd; | ||
540 | mvdev->virtio_id = type; | ||
541 | vqconfig = mic_vq_config(dd); | ||
542 | INIT_WORK(&mvdev->virtio_bh_work, mic_bh_handler); | ||
543 | |||
544 | for (i = 0; i < dd->num_vq; i++) { | ||
545 | struct mic_vringh *mvr = &mvdev->mvr[i]; | ||
546 | struct mic_vring *vr = &mvdev->mvr[i].vring; | ||
547 | num = le16_to_cpu(vqconfig[i].num); | ||
548 | mutex_init(&mvr->vr_mutex); | ||
549 | vr_size = PAGE_ALIGN(vring_size(num, MIC_VIRTIO_RING_ALIGN) + | ||
550 | sizeof(struct _mic_vring_info)); | ||
551 | vr->va = (void *) | ||
552 | __get_free_pages(GFP_KERNEL | __GFP_ZERO, | ||
553 | get_order(vr_size)); | ||
554 | if (!vr->va) { | ||
555 | ret = -ENOMEM; | ||
556 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
557 | __func__, __LINE__, ret); | ||
558 | goto err; | ||
559 | } | ||
560 | vr->len = vr_size; | ||
561 | vr->info = vr->va + vring_size(num, MIC_VIRTIO_RING_ALIGN); | ||
562 | vr->info->magic = MIC_MAGIC + mvdev->virtio_id + i; | ||
563 | vqconfig[i].address = mic_map_single(mdev, | ||
564 | vr->va, vr_size); | ||
565 | if (mic_map_error(vqconfig[i].address)) { | ||
566 | free_pages((unsigned long)vr->va, get_order(vr_size)); | ||
567 | ret = -ENOMEM; | ||
568 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
569 | __func__, __LINE__, ret); | ||
570 | goto err; | ||
571 | } | ||
572 | vqconfig[i].address = cpu_to_le64(vqconfig[i].address); | ||
573 | |||
574 | vring_init(&vr->vr, num, vr->va, MIC_VIRTIO_RING_ALIGN); | ||
575 | ret = vringh_init_kern(&mvr->vrh, | ||
576 | *(u32 *)mic_vq_features(mvdev->dd), num, false, | ||
577 | vr->vr.desc, vr->vr.avail, vr->vr.used); | ||
578 | if (ret) { | ||
579 | dev_err(mic_dev(mvdev), "%s %d err %d\n", | ||
580 | __func__, __LINE__, ret); | ||
581 | goto err; | ||
582 | } | ||
583 | vringh_kiov_init(&mvr->riov, NULL, 0); | ||
584 | vringh_kiov_init(&mvr->wiov, NULL, 0); | ||
585 | mvr->head = USHRT_MAX; | ||
586 | mvr->mvdev = mvdev; | ||
587 | mvr->vrh.notify = mic_notify; | ||
588 | dev_dbg(mdev->sdev->parent, | ||
589 | "%s %d index %d va %p info %p vr_size 0x%x\n", | ||
590 | __func__, __LINE__, i, vr->va, vr->info, vr_size); | ||
591 | } | ||
592 | |||
593 | snprintf(irqname, sizeof(irqname), "mic%dvirtio%d", mdev->id, | ||
594 | mvdev->virtio_id); | ||
595 | mvdev->virtio_db = mic_next_db(mdev); | ||
596 | mvdev->virtio_cookie = mic_request_irq(mdev, mic_virtio_intr_handler, | ||
597 | irqname, mvdev, mvdev->virtio_db, MIC_INTR_DB); | ||
598 | if (IS_ERR(mvdev->virtio_cookie)) { | ||
599 | ret = PTR_ERR(mvdev->virtio_cookie); | ||
600 | dev_dbg(mdev->sdev->parent, "request irq failed\n"); | ||
601 | goto err; | ||
602 | } | ||
603 | |||
604 | mvdev->dc->c2h_vdev_db = mvdev->virtio_db; | ||
605 | |||
606 | list_add_tail(&mvdev->list, &mdev->vdev_list); | ||
607 | /* | ||
608 | * Order the type update with previous stores. This write barrier | ||
609 | * is paired with the corresponding read barrier before the uncached | ||
610 | * system memory read of the type, on the card while scanning the | ||
611 | * device page. | ||
612 | */ | ||
613 | smp_wmb(); | ||
614 | dd->type = type; | ||
615 | |||
616 | dev_dbg(mdev->sdev->parent, "Added virtio device id %d\n", dd->type); | ||
617 | |||
618 | db = bootparam->h2c_config_db; | ||
619 | if (db != -1) | ||
620 | mdev->ops->send_intr(mdev, db); | ||
621 | mutex_unlock(&mdev->mic_mutex); | ||
622 | return 0; | ||
623 | err: | ||
624 | vqconfig = mic_vq_config(dd); | ||
625 | for (j = 0; j < i; j++) { | ||
626 | struct mic_vringh *mvr = &mvdev->mvr[j]; | ||
627 | mic_unmap_single(mdev, le64_to_cpu(vqconfig[j].address), | ||
628 | mvr->vring.len); | ||
629 | free_pages((unsigned long)mvr->vring.va, | ||
630 | get_order(mvr->vring.len)); | ||
631 | } | ||
632 | mutex_unlock(&mdev->mic_mutex); | ||
633 | return ret; | ||
634 | } | ||
635 | |||
636 | void mic_virtio_del_device(struct mic_vdev *mvdev) | ||
637 | { | ||
638 | struct list_head *pos, *tmp; | ||
639 | struct mic_vdev *tmp_mvdev; | ||
640 | struct mic_device *mdev = mvdev->mdev; | ||
641 | DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake); | ||
642 | int i, ret, retry = 100; | ||
643 | struct mic_vqconfig *vqconfig; | ||
644 | struct mic_bootparam *bootparam = mdev->dp; | ||
645 | s8 db; | ||
646 | |||
647 | mutex_lock(&mdev->mic_mutex); | ||
648 | db = bootparam->h2c_config_db; | ||
649 | if (db == -1) | ||
650 | goto skip_hot_remove; | ||
651 | dev_dbg(mdev->sdev->parent, | ||
652 | "Requesting hot remove id %d\n", mvdev->virtio_id); | ||
653 | mvdev->dc->config_change = MIC_VIRTIO_PARAM_DEV_REMOVE; | ||
654 | mdev->ops->send_intr(mdev, db); | ||
655 | for (i = retry; i--;) { | ||
656 | ret = wait_event_timeout(wake, | ||
657 | mvdev->dc->guest_ack, msecs_to_jiffies(100)); | ||
658 | if (ret) | ||
659 | break; | ||
660 | } | ||
661 | dev_dbg(mdev->sdev->parent, | ||
662 | "Device id %d config_change %d guest_ack %d\n", | ||
663 | mvdev->virtio_id, mvdev->dc->config_change, | ||
664 | mvdev->dc->guest_ack); | ||
665 | mvdev->dc->config_change = 0; | ||
666 | mvdev->dc->guest_ack = 0; | ||
667 | skip_hot_remove: | ||
668 | mic_free_irq(mdev, mvdev->virtio_cookie, mvdev); | ||
669 | flush_work(&mvdev->virtio_bh_work); | ||
670 | vqconfig = mic_vq_config(mvdev->dd); | ||
671 | for (i = 0; i < mvdev->dd->num_vq; i++) { | ||
672 | struct mic_vringh *mvr = &mvdev->mvr[i]; | ||
673 | vringh_kiov_cleanup(&mvr->riov); | ||
674 | vringh_kiov_cleanup(&mvr->wiov); | ||
675 | mic_unmap_single(mdev, le64_to_cpu(vqconfig[i].address), | ||
676 | mvr->vring.len); | ||
677 | free_pages((unsigned long)mvr->vring.va, | ||
678 | get_order(mvr->vring.len)); | ||
679 | } | ||
680 | |||
681 | list_for_each_safe(pos, tmp, &mdev->vdev_list) { | ||
682 | tmp_mvdev = list_entry(pos, struct mic_vdev, list); | ||
683 | if (tmp_mvdev == mvdev) { | ||
684 | list_del(pos); | ||
685 | dev_dbg(mdev->sdev->parent, | ||
686 | "Removing virtio device id %d\n", | ||
687 | mvdev->virtio_id); | ||
688 | break; | ||
689 | } | ||
690 | } | ||
691 | /* | ||
692 | * Order the type update with previous stores. This write barrier | ||
693 | * is paired with the corresponding read barrier before the uncached | ||
694 | * system memory read of the type, on the card while scanning the | ||
695 | * device page. | ||
696 | */ | ||
697 | smp_wmb(); | ||
698 | mvdev->dd->type = -1; | ||
699 | mutex_unlock(&mdev->mic_mutex); | ||
700 | } | ||
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..81e9541b784c --- /dev/null +++ b/drivers/misc/mic/host/mic_x100.c | |||
@@ -0,0 +1,570 @@ | |||
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_dev.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, MIC_X100_SBOX_BASE_ADDRESS + | ||
134 | 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, " %s", mdev->cmdline); | ||
369 | memcpy_toio(cmd_line_va, buf, strlen(buf) + 1); | ||
370 | kfree(buf); | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | /** | ||
375 | * mic_x100_load_ramdisk - Load ramdisk to MIC. | ||
376 | * @mdev: pointer to mic_device instance | ||
377 | * | ||
378 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
379 | */ | ||
380 | static int | ||
381 | mic_x100_load_ramdisk(struct mic_device *mdev) | ||
382 | { | ||
383 | const struct firmware *fw; | ||
384 | int rc; | ||
385 | struct boot_params __iomem *bp = mdev->aper.va + mdev->bootaddr; | ||
386 | |||
387 | rc = request_firmware(&fw, | ||
388 | mdev->ramdisk, mdev->sdev->parent); | ||
389 | if (rc < 0) { | ||
390 | dev_err(mdev->sdev->parent, | ||
391 | "ramdisk request_firmware failed: %d %s\n", | ||
392 | rc, mdev->ramdisk); | ||
393 | goto error; | ||
394 | } | ||
395 | /* | ||
396 | * Typically the bootaddr for card OS is 64M | ||
397 | * so copy over the ramdisk @ 128M. | ||
398 | */ | ||
399 | memcpy_toio(mdev->aper.va + (mdev->bootaddr << 1), fw->data, fw->size); | ||
400 | iowrite32(cpu_to_le32(mdev->bootaddr << 1), &bp->hdr.ramdisk_image); | ||
401 | iowrite32(cpu_to_le32(fw->size), &bp->hdr.ramdisk_size); | ||
402 | release_firmware(fw); | ||
403 | error: | ||
404 | return rc; | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * mic_x100_get_boot_addr - Get MIC boot address. | ||
409 | * @mdev: pointer to mic_device instance | ||
410 | * | ||
411 | * This function is called during firmware load to determine | ||
412 | * the address at which the OS should be downloaded in card | ||
413 | * memory i.e. GDDR. | ||
414 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
415 | */ | ||
416 | static int | ||
417 | mic_x100_get_boot_addr(struct mic_device *mdev) | ||
418 | { | ||
419 | u32 scratch2, boot_addr; | ||
420 | int rc = 0; | ||
421 | |||
422 | scratch2 = mdev->ops->read_spad(mdev, MIC_X100_DOWNLOAD_INFO); | ||
423 | boot_addr = MIC_X100_SPAD2_DOWNLOAD_ADDR(scratch2); | ||
424 | dev_dbg(mdev->sdev->parent, "%s %d boot_addr 0x%x\n", | ||
425 | __func__, __LINE__, boot_addr); | ||
426 | if (boot_addr > (1 << 31)) { | ||
427 | dev_err(mdev->sdev->parent, | ||
428 | "incorrect bootaddr 0x%x\n", | ||
429 | boot_addr); | ||
430 | rc = -EINVAL; | ||
431 | goto error; | ||
432 | } | ||
433 | mdev->bootaddr = boot_addr; | ||
434 | error: | ||
435 | return rc; | ||
436 | } | ||
437 | |||
438 | /** | ||
439 | * mic_x100_load_firmware - Load firmware to MIC. | ||
440 | * @mdev: pointer to mic_device instance | ||
441 | * @buf: buffer containing boot string including firmware/ramdisk path. | ||
442 | * | ||
443 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | ||
444 | */ | ||
445 | static int | ||
446 | mic_x100_load_firmware(struct mic_device *mdev, const char *buf) | ||
447 | { | ||
448 | int rc; | ||
449 | const struct firmware *fw; | ||
450 | |||
451 | rc = mic_x100_get_boot_addr(mdev); | ||
452 | if (rc) | ||
453 | goto error; | ||
454 | /* load OS */ | ||
455 | rc = request_firmware(&fw, mdev->firmware, mdev->sdev->parent); | ||
456 | if (rc < 0) { | ||
457 | dev_err(mdev->sdev->parent, | ||
458 | "ramdisk request_firmware failed: %d %s\n", | ||
459 | rc, mdev->firmware); | ||
460 | goto error; | ||
461 | } | ||
462 | if (mdev->bootaddr > mdev->aper.len - fw->size) { | ||
463 | rc = -EINVAL; | ||
464 | dev_err(mdev->sdev->parent, "%s %d rc %d bootaddr 0x%x\n", | ||
465 | __func__, __LINE__, rc, mdev->bootaddr); | ||
466 | release_firmware(fw); | ||
467 | goto error; | ||
468 | } | ||
469 | memcpy_toio(mdev->aper.va + mdev->bootaddr, fw->data, fw->size); | ||
470 | mdev->ops->write_spad(mdev, MIC_X100_FW_SIZE, fw->size); | ||
471 | if (!strcmp(mdev->bootmode, "elf")) | ||
472 | goto done; | ||
473 | /* load command line */ | ||
474 | rc = mic_x100_load_command_line(mdev, fw); | ||
475 | if (rc) { | ||
476 | dev_err(mdev->sdev->parent, "%s %d rc %d\n", | ||
477 | __func__, __LINE__, rc); | ||
478 | goto error; | ||
479 | } | ||
480 | release_firmware(fw); | ||
481 | /* load ramdisk */ | ||
482 | if (mdev->ramdisk) | ||
483 | rc = mic_x100_load_ramdisk(mdev); | ||
484 | error: | ||
485 | dev_dbg(mdev->sdev->parent, "%s %d rc %d\n", __func__, __LINE__, rc); | ||
486 | done: | ||
487 | return rc; | ||
488 | } | ||
489 | |||
490 | /** | ||
491 | * mic_x100_get_postcode - Get postcode status from firmware. | ||
492 | * @mdev: pointer to mic_device instance | ||
493 | * | ||
494 | * RETURNS: postcode. | ||
495 | */ | ||
496 | static u32 mic_x100_get_postcode(struct mic_device *mdev) | ||
497 | { | ||
498 | return mic_mmio_read(&mdev->mmio, MIC_X100_POSTCODE); | ||
499 | } | ||
500 | |||
501 | /** | ||
502 | * mic_x100_smpt_set - Update an SMPT entry with a DMA address. | ||
503 | * @mdev: pointer to mic_device instance | ||
504 | * | ||
505 | * RETURNS: none. | ||
506 | */ | ||
507 | static void | ||
508 | mic_x100_smpt_set(struct mic_device *mdev, dma_addr_t dma_addr, u8 index) | ||
509 | { | ||
510 | #define SNOOP_ON (0 << 0) | ||
511 | #define SNOOP_OFF (1 << 0) | ||
512 | /* | ||
513 | * Sbox Smpt Reg Bits: | ||
514 | * Bits 31:2 Host address | ||
515 | * Bits 1 RSVD | ||
516 | * Bits 0 No snoop | ||
517 | */ | ||
518 | #define BUILD_SMPT(NO_SNOOP, HOST_ADDR) \ | ||
519 | (u32)(((HOST_ADDR) << 2) | ((NO_SNOOP) & 0x01)) | ||
520 | |||
521 | uint32_t smpt_reg_val = BUILD_SMPT(SNOOP_ON, | ||
522 | dma_addr >> mdev->smpt->info.page_shift); | ||
523 | mic_mmio_write(&mdev->mmio, smpt_reg_val, | ||
524 | MIC_X100_SBOX_BASE_ADDRESS + | ||
525 | MIC_X100_SBOX_SMPT00 + (4 * index)); | ||
526 | } | ||
527 | |||
528 | /** | ||
529 | * mic_x100_smpt_hw_init - Initialize SMPT X100 specific fields. | ||
530 | * @mdev: pointer to mic_device instance | ||
531 | * | ||
532 | * RETURNS: none. | ||
533 | */ | ||
534 | static void mic_x100_smpt_hw_init(struct mic_device *mdev) | ||
535 | { | ||
536 | struct mic_smpt_hw_info *info = &mdev->smpt->info; | ||
537 | |||
538 | info->num_reg = 32; | ||
539 | info->page_shift = 34; | ||
540 | info->page_size = (1ULL << info->page_shift); | ||
541 | info->base = 0x8000000000ULL; | ||
542 | } | ||
543 | |||
544 | struct mic_smpt_ops mic_x100_smpt_ops = { | ||
545 | .init = mic_x100_smpt_hw_init, | ||
546 | .set = mic_x100_smpt_set, | ||
547 | }; | ||
548 | |||
549 | struct mic_hw_ops mic_x100_ops = { | ||
550 | .aper_bar = MIC_X100_APER_BAR, | ||
551 | .mmio_bar = MIC_X100_MMIO_BAR, | ||
552 | .read_spad = mic_x100_read_spad, | ||
553 | .write_spad = mic_x100_write_spad, | ||
554 | .send_intr = mic_x100_send_intr, | ||
555 | .ack_interrupt = mic_x100_ack_interrupt, | ||
556 | .reset = mic_x100_hw_reset, | ||
557 | .reset_fw_ready = mic_x100_reset_fw_ready, | ||
558 | .is_fw_ready = mic_x100_is_fw_ready, | ||
559 | .send_firmware_intr = mic_x100_send_firmware_intr, | ||
560 | .load_mic_fw = mic_x100_load_firmware, | ||
561 | .get_postcode = mic_x100_get_postcode, | ||
562 | }; | ||
563 | |||
564 | struct mic_hw_intr_ops mic_x100_intr_ops = { | ||
565 | .intr_init = mic_x100_hw_intr_init, | ||
566 | .enable_interrupts = mic_x100_enable_interrupts, | ||
567 | .disable_interrupts = mic_x100_disable_interrupts, | ||
568 | .program_msi_to_src_map = mic_x100_program_msi_to_src_map, | ||
569 | .read_msi_to_src_map = mic_x100_read_msi_to_src_map, | ||
570 | }; | ||
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/phantom.c b/drivers/misc/phantom.c index 68b7c773d2cf..30754927fd80 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c | |||
@@ -395,7 +395,7 @@ static int phantom_probe(struct pci_dev *pdev, | |||
395 | iowrite32(0, pht->caddr + PHN_IRQCTL); | 395 | iowrite32(0, pht->caddr + PHN_IRQCTL); |
396 | ioread32(pht->caddr + PHN_IRQCTL); /* PCI posting */ | 396 | ioread32(pht->caddr + PHN_IRQCTL); /* PCI posting */ |
397 | retval = request_irq(pdev->irq, phantom_isr, | 397 | retval = request_irq(pdev->irq, phantom_isr, |
398 | IRQF_SHARED | IRQF_DISABLED, "phantom", pht); | 398 | IRQF_SHARED, "phantom", pht); |
399 | if (retval) { | 399 | if (retval) { |
400 | dev_err(&pdev->dev, "can't establish ISR\n"); | 400 | dev_err(&pdev->dev, "can't establish ISR\n"); |
401 | goto err_unmo; | 401 | goto err_unmo; |
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..a606c8901e18 100644 --- a/drivers/misc/tifm_7xx1.c +++ b/drivers/misc/tifm_7xx1.c | |||
@@ -356,8 +356,10 @@ static int tifm_7xx1_probe(struct pci_dev *dev, | |||
356 | pci_set_drvdata(dev, fm); | 356 | pci_set_drvdata(dev, fm); |
357 | 357 | ||
358 | fm->addr = pci_ioremap_bar(dev, 0); | 358 | fm->addr = pci_ioremap_bar(dev, 0); |
359 | if (!fm->addr) | 359 | if (!fm->addr) { |
360 | rc = -ENODEV; | ||
360 | goto err_out_free; | 361 | goto err_out_free; |
362 | } | ||
361 | 363 | ||
362 | rc = request_irq(dev->irq, tifm_7xx1_isr, IRQF_SHARED, DRIVER_NAME, fm); | 364 | rc = request_irq(dev->irq, tifm_7xx1_isr, IRQF_SHARED, DRIVER_NAME, fm); |
363 | if (rc) | 365 | if (rc) |
@@ -378,7 +380,6 @@ err_out_irq: | |||
378 | err_out_unmap: | 380 | err_out_unmap: |
379 | iounmap(fm->addr); | 381 | iounmap(fm->addr); |
380 | err_out_free: | 382 | err_out_free: |
381 | pci_set_drvdata(dev, NULL); | ||
382 | tifm_free_adapter(fm); | 383 | tifm_free_adapter(fm); |
383 | err_out_int: | 384 | err_out_int: |
384 | pci_intx(dev, 0); | 385 | pci_intx(dev, 0); |
@@ -405,8 +406,6 @@ static void tifm_7xx1_remove(struct pci_dev *dev) | |||
405 | for (cnt = 0; cnt < fm->num_sockets; cnt++) | 406 | for (cnt = 0; cnt < fm->num_sockets; cnt++) |
406 | tifm_7xx1_sock_power_off(tifm_7xx1_sock_addr(fm->addr, cnt)); | 407 | tifm_7xx1_sock_power_off(tifm_7xx1_sock_addr(fm->addr, cnt)); |
407 | 408 | ||
408 | pci_set_drvdata(dev, NULL); | ||
409 | |||
410 | iounmap(fm->addr); | 409 | iounmap(fm->addr); |
411 | pci_intx(dev, 0); | 410 | pci_intx(dev, 0); |
412 | pci_release_regions(dev); | 411 | 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/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c index d4722b3dc8ec..1723a6e4f2e8 100644 --- a/drivers/misc/vmw_vmci/vmci_host.c +++ b/drivers/misc/vmw_vmci/vmci_host.c | |||
@@ -243,11 +243,7 @@ static int vmci_host_setup_notify(struct vmci_ctx *context, | |||
243 | /* | 243 | /* |
244 | * Lock physical page backing a given user VA. | 244 | * Lock physical page backing a given user VA. |
245 | */ | 245 | */ |
246 | down_read(¤t->mm->mmap_sem); | 246 | retval = get_user_pages_fast(PAGE_ALIGN(uva), 1, 1, &page); |
247 | retval = get_user_pages(current, current->mm, | ||
248 | PAGE_ALIGN(uva), | ||
249 | 1, 1, 0, &page, NULL); | ||
250 | up_read(¤t->mm->mmap_sem); | ||
251 | if (retval != 1) | 247 | if (retval != 1) |
252 | return VMCI_ERROR_GENERIC; | 248 | return VMCI_ERROR_GENERIC; |
253 | 249 | ||
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c index a0515a6d6ebd..1b7b303085d2 100644 --- a/drivers/misc/vmw_vmci/vmci_queue_pair.c +++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c | |||
@@ -732,13 +732,9 @@ static int qp_host_get_user_memory(u64 produce_uva, | |||
732 | int retval; | 732 | int retval; |
733 | int err = VMCI_SUCCESS; | 733 | int err = VMCI_SUCCESS; |
734 | 734 | ||
735 | down_write(¤t->mm->mmap_sem); | 735 | retval = get_user_pages_fast((uintptr_t) produce_uva, |
736 | retval = get_user_pages(current, | 736 | produce_q->kernel_if->num_pages, 1, |
737 | current->mm, | 737 | produce_q->kernel_if->u.h.header_page); |
738 | (uintptr_t) produce_uva, | ||
739 | produce_q->kernel_if->num_pages, | ||
740 | 1, 0, | ||
741 | produce_q->kernel_if->u.h.header_page, NULL); | ||
742 | if (retval < produce_q->kernel_if->num_pages) { | 738 | if (retval < produce_q->kernel_if->num_pages) { |
743 | pr_warn("get_user_pages(produce) failed (retval=%d)", retval); | 739 | pr_warn("get_user_pages(produce) failed (retval=%d)", retval); |
744 | qp_release_pages(produce_q->kernel_if->u.h.header_page, | 740 | qp_release_pages(produce_q->kernel_if->u.h.header_page, |
@@ -747,12 +743,9 @@ static int qp_host_get_user_memory(u64 produce_uva, | |||
747 | goto out; | 743 | goto out; |
748 | } | 744 | } |
749 | 745 | ||
750 | retval = get_user_pages(current, | 746 | retval = get_user_pages_fast((uintptr_t) consume_uva, |
751 | current->mm, | 747 | consume_q->kernel_if->num_pages, 1, |
752 | (uintptr_t) consume_uva, | 748 | consume_q->kernel_if->u.h.header_page); |
753 | consume_q->kernel_if->num_pages, | ||
754 | 1, 0, | ||
755 | consume_q->kernel_if->u.h.header_page, NULL); | ||
756 | if (retval < consume_q->kernel_if->num_pages) { | 749 | if (retval < consume_q->kernel_if->num_pages) { |
757 | pr_warn("get_user_pages(consume) failed (retval=%d)", retval); | 750 | pr_warn("get_user_pages(consume) failed (retval=%d)", retval); |
758 | qp_release_pages(consume_q->kernel_if->u.h.header_page, | 751 | qp_release_pages(consume_q->kernel_if->u.h.header_page, |
@@ -763,8 +756,6 @@ static int qp_host_get_user_memory(u64 produce_uva, | |||
763 | } | 756 | } |
764 | 757 | ||
765 | out: | 758 | out: |
766 | up_write(¤t->mm->mmap_sem); | ||
767 | |||
768 | return err; | 759 | return err; |
769 | } | 760 | } |
770 | 761 | ||
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 0e808cf91d97..67beb8444930 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c | |||
@@ -288,13 +288,13 @@ static int uio_dev_add_attributes(struct uio_device *idev) | |||
288 | } | 288 | } |
289 | map = kzalloc(sizeof(*map), GFP_KERNEL); | 289 | map = kzalloc(sizeof(*map), GFP_KERNEL); |
290 | if (!map) | 290 | if (!map) |
291 | goto err_map; | 291 | goto err_map_kobj; |
292 | kobject_init(&map->kobj, &map_attr_type); | 292 | kobject_init(&map->kobj, &map_attr_type); |
293 | map->mem = mem; | 293 | map->mem = mem; |
294 | mem->map = map; | 294 | mem->map = map; |
295 | ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi); | 295 | ret = kobject_add(&map->kobj, idev->map_dir, "map%d", mi); |
296 | if (ret) | 296 | if (ret) |
297 | goto err_map; | 297 | goto err_map_kobj; |
298 | ret = kobject_uevent(&map->kobj, KOBJ_ADD); | 298 | ret = kobject_uevent(&map->kobj, KOBJ_ADD); |
299 | if (ret) | 299 | if (ret) |
300 | goto err_map; | 300 | goto err_map; |
@@ -313,14 +313,14 @@ static int uio_dev_add_attributes(struct uio_device *idev) | |||
313 | } | 313 | } |
314 | portio = kzalloc(sizeof(*portio), GFP_KERNEL); | 314 | portio = kzalloc(sizeof(*portio), GFP_KERNEL); |
315 | if (!portio) | 315 | if (!portio) |
316 | goto err_portio; | 316 | goto err_portio_kobj; |
317 | kobject_init(&portio->kobj, &portio_attr_type); | 317 | kobject_init(&portio->kobj, &portio_attr_type); |
318 | portio->port = port; | 318 | portio->port = port; |
319 | port->portio = portio; | 319 | port->portio = portio; |
320 | ret = kobject_add(&portio->kobj, idev->portio_dir, | 320 | ret = kobject_add(&portio->kobj, idev->portio_dir, |
321 | "port%d", pi); | 321 | "port%d", pi); |
322 | if (ret) | 322 | if (ret) |
323 | goto err_portio; | 323 | goto err_portio_kobj; |
324 | ret = kobject_uevent(&portio->kobj, KOBJ_ADD); | 324 | ret = kobject_uevent(&portio->kobj, KOBJ_ADD); |
325 | if (ret) | 325 | if (ret) |
326 | goto err_portio; | 326 | goto err_portio; |
@@ -329,14 +329,18 @@ static int uio_dev_add_attributes(struct uio_device *idev) | |||
329 | return 0; | 329 | return 0; |
330 | 330 | ||
331 | err_portio: | 331 | err_portio: |
332 | for (pi--; pi >= 0; pi--) { | 332 | pi--; |
333 | err_portio_kobj: | ||
334 | for (; pi >= 0; pi--) { | ||
333 | port = &idev->info->port[pi]; | 335 | port = &idev->info->port[pi]; |
334 | portio = port->portio; | 336 | portio = port->portio; |
335 | kobject_put(&portio->kobj); | 337 | kobject_put(&portio->kobj); |
336 | } | 338 | } |
337 | kobject_put(idev->portio_dir); | 339 | kobject_put(idev->portio_dir); |
338 | err_map: | 340 | err_map: |
339 | for (mi--; mi>=0; mi--) { | 341 | mi--; |
342 | err_map_kobj: | ||
343 | for (; mi >= 0; mi--) { | ||
340 | mem = &idev->info->mem[mi]; | 344 | mem = &idev->info->mem[mi]; |
341 | map = mem->map; | 345 | map = mem->map; |
342 | kobject_put(&map->kobj); | 346 | kobject_put(&map->kobj); |
@@ -601,6 +605,7 @@ static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
601 | struct uio_device *idev = vma->vm_private_data; | 605 | struct uio_device *idev = vma->vm_private_data; |
602 | struct page *page; | 606 | struct page *page; |
603 | unsigned long offset; | 607 | unsigned long offset; |
608 | void *addr; | ||
604 | 609 | ||
605 | int mi = uio_find_mem_index(vma); | 610 | int mi = uio_find_mem_index(vma); |
606 | if (mi < 0) | 611 | if (mi < 0) |
@@ -612,10 +617,11 @@ static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
612 | */ | 617 | */ |
613 | offset = (vmf->pgoff - mi) << PAGE_SHIFT; | 618 | offset = (vmf->pgoff - mi) << PAGE_SHIFT; |
614 | 619 | ||
620 | addr = (void *)(unsigned long)idev->info->mem[mi].addr + offset; | ||
615 | if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL) | 621 | if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL) |
616 | page = virt_to_page(idev->info->mem[mi].addr + offset); | 622 | page = virt_to_page(addr); |
617 | else | 623 | else |
618 | page = vmalloc_to_page((void *)(unsigned long)idev->info->mem[mi].addr + offset); | 624 | page = vmalloc_to_page(addr); |
619 | get_page(page); | 625 | get_page(page); |
620 | vmf->page = page; | 626 | vmf->page = page; |
621 | return 0; | 627 | return 0; |
@@ -809,10 +815,9 @@ int __uio_register_device(struct module *owner, | |||
809 | 815 | ||
810 | info->uio_dev = NULL; | 816 | info->uio_dev = NULL; |
811 | 817 | ||
812 | idev = kzalloc(sizeof(*idev), GFP_KERNEL); | 818 | idev = devm_kzalloc(parent, sizeof(*idev), GFP_KERNEL); |
813 | if (!idev) { | 819 | if (!idev) { |
814 | ret = -ENOMEM; | 820 | return -ENOMEM; |
815 | goto err_kzalloc; | ||
816 | } | 821 | } |
817 | 822 | ||
818 | idev->owner = owner; | 823 | idev->owner = owner; |
@@ -822,7 +827,7 @@ int __uio_register_device(struct module *owner, | |||
822 | 827 | ||
823 | ret = uio_get_minor(idev); | 828 | ret = uio_get_minor(idev); |
824 | if (ret) | 829 | if (ret) |
825 | goto err_get_minor; | 830 | return ret; |
826 | 831 | ||
827 | idev->dev = device_create(&uio_class, parent, | 832 | idev->dev = device_create(&uio_class, parent, |
828 | MKDEV(uio_major, idev->minor), idev, | 833 | MKDEV(uio_major, idev->minor), idev, |
@@ -840,7 +845,7 @@ int __uio_register_device(struct module *owner, | |||
840 | info->uio_dev = idev; | 845 | info->uio_dev = idev; |
841 | 846 | ||
842 | if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { | 847 | if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) { |
843 | ret = request_irq(info->irq, uio_interrupt, | 848 | ret = devm_request_irq(parent, info->irq, uio_interrupt, |
844 | info->irq_flags, info->name, idev); | 849 | info->irq_flags, info->name, idev); |
845 | if (ret) | 850 | if (ret) |
846 | goto err_request_irq; | 851 | goto err_request_irq; |
@@ -854,9 +859,6 @@ err_uio_dev_add_attributes: | |||
854 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); | 859 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); |
855 | err_device_create: | 860 | err_device_create: |
856 | uio_free_minor(idev); | 861 | uio_free_minor(idev); |
857 | err_get_minor: | ||
858 | kfree(idev); | ||
859 | err_kzalloc: | ||
860 | return ret; | 862 | return ret; |
861 | } | 863 | } |
862 | EXPORT_SYMBOL_GPL(__uio_register_device); | 864 | EXPORT_SYMBOL_GPL(__uio_register_device); |
@@ -877,13 +879,9 @@ void uio_unregister_device(struct uio_info *info) | |||
877 | 879 | ||
878 | uio_free_minor(idev); | 880 | uio_free_minor(idev); |
879 | 881 | ||
880 | if (info->irq && (info->irq != UIO_IRQ_CUSTOM)) | ||
881 | free_irq(info->irq, idev); | ||
882 | |||
883 | uio_dev_del_attributes(idev); | 882 | uio_dev_del_attributes(idev); |
884 | 883 | ||
885 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); | 884 | device_destroy(&uio_class, MKDEV(uio_major, idev->minor)); |
886 | kfree(idev); | ||
887 | 885 | ||
888 | return; | 886 | return; |
889 | } | 887 | } |
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); |
diff --git a/drivers/w1/masters/ds1wm.c b/drivers/w1/masters/ds1wm.c index 96cab6ac2b4e..41613f92a723 100644 --- a/drivers/w1/masters/ds1wm.c +++ b/drivers/w1/masters/ds1wm.c | |||
@@ -498,7 +498,7 @@ static int ds1wm_probe(struct platform_device *pdev) | |||
498 | irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING); | 498 | irq_set_irq_type(ds1wm_data->irq, IRQ_TYPE_EDGE_FALLING); |
499 | 499 | ||
500 | ret = devm_request_irq(&pdev->dev, ds1wm_data->irq, ds1wm_isr, | 500 | ret = devm_request_irq(&pdev->dev, ds1wm_data->irq, ds1wm_isr, |
501 | IRQF_DISABLED | IRQF_SHARED, "ds1wm", ds1wm_data); | 501 | IRQF_SHARED, "ds1wm", ds1wm_data); |
502 | if (ret) | 502 | if (ret) |
503 | return ret; | 503 | return ret; |
504 | 504 | ||
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c index 6e94d8dd3d00..9900e8ec7393 100644 --- a/drivers/w1/masters/omap_hdq.c +++ b/drivers/w1/masters/omap_hdq.c | |||
@@ -577,8 +577,7 @@ static int omap_hdq_probe(struct platform_device *pdev) | |||
577 | goto err_irq; | 577 | goto err_irq; |
578 | } | 578 | } |
579 | 579 | ||
580 | ret = devm_request_irq(dev, irq, hdq_isr, IRQF_DISABLED, | 580 | ret = devm_request_irq(dev, irq, hdq_isr, 0, "omap_hdq", hdq_data); |
581 | "omap_hdq", hdq_data); | ||
582 | if (ret < 0) { | 581 | if (ret < 0) { |
583 | dev_dbg(&pdev->dev, "could not request irq\n"); | 582 | dev_dbg(&pdev->dev, "could not request irq\n"); |
584 | goto err_irq; | 583 | goto err_irq; |
diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c index f54ece268c98..264ad1c583ab 100644 --- a/drivers/w1/masters/w1-gpio.c +++ b/drivers/w1/masters/w1-gpio.c | |||
@@ -58,6 +58,7 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) | |||
58 | { | 58 | { |
59 | struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; | 59 | struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; |
60 | struct device_node *np = pdev->dev.of_node; | 60 | struct device_node *np = pdev->dev.of_node; |
61 | int gpio; | ||
61 | 62 | ||
62 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | 63 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
63 | if (!pdata) | 64 | if (!pdata) |
@@ -66,7 +67,11 @@ static int w1_gpio_probe_dt(struct platform_device *pdev) | |||
66 | if (of_get_property(np, "linux,open-drain", NULL)) | 67 | if (of_get_property(np, "linux,open-drain", NULL)) |
67 | pdata->is_open_drain = 1; | 68 | pdata->is_open_drain = 1; |
68 | 69 | ||
69 | pdata->pin = of_get_gpio(np, 0); | 70 | gpio = of_get_gpio(np, 0); |
71 | if (gpio < 0) | ||
72 | return gpio; | ||
73 | pdata->pin = gpio; | ||
74 | |||
70 | pdata->ext_pullup_enable_pin = of_get_gpio(np, 1); | 75 | pdata->ext_pullup_enable_pin = of_get_gpio(np, 1); |
71 | pdev->dev.platform_data = pdata; | 76 | pdev->dev.platform_data = pdata; |
72 | 77 | ||
@@ -94,25 +99,27 @@ static int w1_gpio_probe(struct platform_device *pdev) | |||
94 | return -ENXIO; | 99 | return -ENXIO; |
95 | } | 100 | } |
96 | 101 | ||
97 | master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL); | 102 | master = devm_kzalloc(&pdev->dev, sizeof(struct w1_bus_master), |
103 | GFP_KERNEL); | ||
98 | if (!master) { | 104 | if (!master) { |
99 | dev_err(&pdev->dev, "Out of memory\n"); | 105 | dev_err(&pdev->dev, "Out of memory\n"); |
100 | return -ENOMEM; | 106 | return -ENOMEM; |
101 | } | 107 | } |
102 | 108 | ||
103 | err = gpio_request(pdata->pin, "w1"); | 109 | err = devm_gpio_request(&pdev->dev, pdata->pin, "w1"); |
104 | if (err) { | 110 | if (err) { |
105 | dev_err(&pdev->dev, "gpio_request (pin) failed\n"); | 111 | dev_err(&pdev->dev, "gpio_request (pin) failed\n"); |
106 | goto free_master; | 112 | return err; |
107 | } | 113 | } |
108 | 114 | ||
109 | if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { | 115 | if (gpio_is_valid(pdata->ext_pullup_enable_pin)) { |
110 | err = gpio_request_one(pdata->ext_pullup_enable_pin, | 116 | err = devm_gpio_request_one(&pdev->dev, |
111 | GPIOF_INIT_LOW, "w1 pullup"); | 117 | pdata->ext_pullup_enable_pin, GPIOF_INIT_LOW, |
118 | "w1 pullup"); | ||
112 | if (err < 0) { | 119 | if (err < 0) { |
113 | dev_err(&pdev->dev, "gpio_request_one " | 120 | dev_err(&pdev->dev, "gpio_request_one " |
114 | "(ext_pullup_enable_pin) failed\n"); | 121 | "(ext_pullup_enable_pin) failed\n"); |
115 | goto free_gpio; | 122 | return err; |
116 | } | 123 | } |
117 | } | 124 | } |
118 | 125 | ||
@@ -130,7 +137,7 @@ static int w1_gpio_probe(struct platform_device *pdev) | |||
130 | err = w1_add_master_device(master); | 137 | err = w1_add_master_device(master); |
131 | if (err) { | 138 | if (err) { |
132 | dev_err(&pdev->dev, "w1_add_master device failed\n"); | 139 | dev_err(&pdev->dev, "w1_add_master device failed\n"); |
133 | goto free_gpio_ext_pu; | 140 | return err; |
134 | } | 141 | } |
135 | 142 | ||
136 | if (pdata->enable_external_pullup) | 143 | if (pdata->enable_external_pullup) |
@@ -142,16 +149,6 @@ static int w1_gpio_probe(struct platform_device *pdev) | |||
142 | platform_set_drvdata(pdev, master); | 149 | platform_set_drvdata(pdev, master); |
143 | 150 | ||
144 | return 0; | 151 | return 0; |
145 | |||
146 | free_gpio_ext_pu: | ||
147 | if (gpio_is_valid(pdata->ext_pullup_enable_pin)) | ||
148 | gpio_free(pdata->ext_pullup_enable_pin); | ||
149 | free_gpio: | ||
150 | gpio_free(pdata->pin); | ||
151 | free_master: | ||
152 | kfree(master); | ||
153 | |||
154 | return err; | ||
155 | } | 152 | } |
156 | 153 | ||
157 | static int w1_gpio_remove(struct platform_device *pdev) | 154 | static int w1_gpio_remove(struct platform_device *pdev) |
@@ -166,8 +163,6 @@ static int w1_gpio_remove(struct platform_device *pdev) | |||
166 | gpio_set_value(pdata->ext_pullup_enable_pin, 0); | 163 | gpio_set_value(pdata->ext_pullup_enable_pin, 0); |
167 | 164 | ||
168 | w1_remove_master_device(master); | 165 | w1_remove_master_device(master); |
169 | gpio_free(pdata->pin); | ||
170 | kfree(master); | ||
171 | 166 | ||
172 | return 0; | 167 | return 0; |
173 | } | 168 | } |