diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-03-31 00:20:41 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-03-31 00:20:41 +0300 |
commit | 4c6ef3b156c67e8867e04668cb2af902d44e4086 (patch) | |
tree | 70f344855985980dd66776bcc5506738d2914441 /drivers/staging/vc04_services | |
parent | 59838093be51ee9447f6ad05483d697b6fa0368d (diff) | |
parent | e681bb287f40e7a9dbcb04cef80fd87a2511ab86 (diff) | |
download | linux-4c6ef3b156c67e8867e04668cb2af902d44e4086.tar.xz |
Merge tag 'staging-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging and IIO driver updates from Greg KH:
"Here is the big staging and IIO driver pull request for 5.7-rc1.
We again end up deleting more code than we added here, thanks to
finally getting rid of the old and obsolete wireless USB stuff, and
the exfat code (which is coming in again through the vfs tree in a
much cleaner version).
But some code does come back, with the octeon drivers being found to
actually be used in the wild, so those deletions are now reverted.
Other than those major things, just loads and loads of tiny checkpatch
cleanups all over the place, along with new IIO drivers and fixes.
All have been in linux-next with no reported issues"
[ Stephen Rothwell points out some reported issues due to merge conflicts ]
* tag 'staging-5.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (415 commits)
staging: vt6656: Use DIV_ROUND_UP macro instead of specific code
staging: remove hp100 driver
staging: wilc1000: Use crc7 in lib/ rather than a private copy
Staging: rtl8192u: ieee80211: Use netdev_alert().
Staging: rtl8192u: ieee80211: Use netdev_info() with network devices.
Staging: rtl8192u: ieee80211: Use netdev_warn() for network devices.
Staging: rtl8192u: ieee80211: Use netdev_dbg() for debug messages.
staging: wlan-ng: fix use-after-free Read in hfa384x_usbin_callback
staging: rtl8723bs: hal: Remove NULL check before kfree
staging: rtl8723bs: hal: Correct typos in comments
staging: rtl8723bs: os_dep: Correct typos in comments
staging: rtl8723bs: core: Correct typos in comments
staging: rtl8723bs: hal: Remove unnecessary cast on void pointer
staging: rtl8188eu: cleanup long line in odm.c
staging: rtl8723bs: hal: Compress return logic
staging: rtl8723bs: rtw_cmd: Compress lines for immediate return
staging: rtl8723bs: rtw_efuse: Compress lines for immediate return
staging: wilc1000: remove label from examples in DT binding documentation
staging: rtl8723bs: Remove blank line before '}' brace
Staging: rtl8188eu: hal: Add space around operators
...
Diffstat (limited to 'drivers/staging/vc04_services')
8 files changed, 507 insertions, 991 deletions
diff --git a/drivers/staging/vc04_services/bcm2835-camera/controls.c b/drivers/staging/vc04_services/bcm2835-camera/controls.c index 89786c264867..5137fcf203d6 100644 --- a/drivers/staging/vc04_services/bcm2835-camera/controls.c +++ b/drivers/staging/vc04_services/bcm2835-camera/controls.c @@ -85,7 +85,6 @@ struct bm2835_mmal_v4l2_ctrl { const s64 *imenu; /* integer menu array */ u32 mmal_id; /* mmal parameter id */ bm2835_mmal_v4l2_ctrl_cb *setter; - bool ignore_errors; }; struct v4l2_to_mmal_effects_setting { @@ -912,8 +911,6 @@ static int bm2835_mmal_s_ctrl(struct v4l2_ctrl *ctrl) if (ret) pr_warn("ctrl id:%d/MMAL param %08X- returned ret %d\n", ctrl->id, mmal_ctrl->mmal_id, ret); - if (mmal_ctrl->ignore_errors) - ret = 0; return ret; } @@ -923,239 +920,340 @@ static const struct v4l2_ctrl_ops bm2835_mmal_ctrl_ops = { static const struct bm2835_mmal_v4l2_ctrl v4l2_ctrls[V4L2_CTRL_COUNT] = { { - V4L2_CID_SATURATION, MMAL_CONTROL_TYPE_STD, - -100, 100, 0, 1, NULL, - MMAL_PARAMETER_SATURATION, - ctrl_set_rational, - false + .id = V4L2_CID_SATURATION, + .type = MMAL_CONTROL_TYPE_STD, + .min = -100, + .max = 100, + .def = 0, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_SATURATION, + .setter = ctrl_set_rational, }, { - V4L2_CID_SHARPNESS, MMAL_CONTROL_TYPE_STD, - -100, 100, 0, 1, NULL, - MMAL_PARAMETER_SHARPNESS, - ctrl_set_rational, - false + .id = V4L2_CID_SHARPNESS, + .type = MMAL_CONTROL_TYPE_STD, + .min = -100, + .max = 100, + .def = 0, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_SHARPNESS, + .setter = ctrl_set_rational, }, { - V4L2_CID_CONTRAST, MMAL_CONTROL_TYPE_STD, - -100, 100, 0, 1, NULL, - MMAL_PARAMETER_CONTRAST, - ctrl_set_rational, - false + .id = V4L2_CID_CONTRAST, + .type = MMAL_CONTROL_TYPE_STD, + .min = -100, + .max = 100, + .def = 0, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_CONTRAST, + .setter = ctrl_set_rational, }, { - V4L2_CID_BRIGHTNESS, MMAL_CONTROL_TYPE_STD, - 0, 100, 50, 1, NULL, - MMAL_PARAMETER_BRIGHTNESS, - ctrl_set_rational, - false + .id = V4L2_CID_BRIGHTNESS, + .type = MMAL_CONTROL_TYPE_STD, + .min = 0, + .max = 100, + .def = 50, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_BRIGHTNESS, + .setter = ctrl_set_rational, }, { - V4L2_CID_ISO_SENSITIVITY, MMAL_CONTROL_TYPE_INT_MENU, - 0, ARRAY_SIZE(iso_qmenu) - 1, 0, 1, iso_qmenu, - MMAL_PARAMETER_ISO, - ctrl_set_iso, - false + .id = V4L2_CID_ISO_SENSITIVITY, + .type = MMAL_CONTROL_TYPE_INT_MENU, + .min = 0, + .max = ARRAY_SIZE(iso_qmenu) - 1, + .def = 0, + .step = 1, + .imenu = iso_qmenu, + .mmal_id = MMAL_PARAMETER_ISO, + .setter = ctrl_set_iso, }, { - V4L2_CID_ISO_SENSITIVITY_AUTO, MMAL_CONTROL_TYPE_STD_MENU, - 0, V4L2_ISO_SENSITIVITY_AUTO, V4L2_ISO_SENSITIVITY_AUTO, 1, - NULL, MMAL_PARAMETER_ISO, - ctrl_set_iso, - false + .id = V4L2_CID_ISO_SENSITIVITY_AUTO, + .type = MMAL_CONTROL_TYPE_STD_MENU, + .min = 0, + .max = V4L2_ISO_SENSITIVITY_AUTO, + .def = V4L2_ISO_SENSITIVITY_AUTO, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_ISO, + .setter = ctrl_set_iso, }, { - V4L2_CID_IMAGE_STABILIZATION, MMAL_CONTROL_TYPE_STD, - 0, 1, 0, 1, NULL, - MMAL_PARAMETER_VIDEO_STABILISATION, - ctrl_set_value, - false + .id = V4L2_CID_IMAGE_STABILIZATION, + .type = MMAL_CONTROL_TYPE_STD, + .min = 0, + .max = 1, + .def = 0, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_VIDEO_STABILISATION, + .setter = ctrl_set_value, }, { - V4L2_CID_EXPOSURE_AUTO, MMAL_CONTROL_TYPE_STD_MENU, - ~0x03, V4L2_EXPOSURE_APERTURE_PRIORITY, V4L2_EXPOSURE_AUTO, 0, - NULL, MMAL_PARAMETER_EXPOSURE_MODE, - ctrl_set_exposure, - false + .id = V4L2_CID_EXPOSURE_AUTO, + .type = MMAL_CONTROL_TYPE_STD_MENU, + .min = ~0x03, + .max = V4L2_EXPOSURE_APERTURE_PRIORITY, + .def = V4L2_EXPOSURE_AUTO, + .step = 0, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_EXPOSURE_MODE, + .setter = ctrl_set_exposure, }, { - V4L2_CID_EXPOSURE_ABSOLUTE, MMAL_CONTROL_TYPE_STD, + .id = V4L2_CID_EXPOSURE_ABSOLUTE, + .type = MMAL_CONTROL_TYPE_STD, /* Units of 100usecs */ - 1, 1 * 1000 * 10, 100 * 10, 1, NULL, - MMAL_PARAMETER_SHUTTER_SPEED, - ctrl_set_exposure, - false + .min = 1, + .max = 1 * 1000 * 10, + .def = 100 * 10, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_SHUTTER_SPEED, + .setter = ctrl_set_exposure, }, { - V4L2_CID_AUTO_EXPOSURE_BIAS, MMAL_CONTROL_TYPE_INT_MENU, - 0, ARRAY_SIZE(ev_bias_qmenu) - 1, - (ARRAY_SIZE(ev_bias_qmenu) + 1) / 2 - 1, 0, ev_bias_qmenu, - MMAL_PARAMETER_EXPOSURE_COMP, - ctrl_set_value_ev, - false + .id = V4L2_CID_AUTO_EXPOSURE_BIAS, + .type = MMAL_CONTROL_TYPE_INT_MENU, + .min = 0, + .max = ARRAY_SIZE(ev_bias_qmenu) - 1, + .def = (ARRAY_SIZE(ev_bias_qmenu) + 1) / 2 - 1, + .step = 0, + .imenu = ev_bias_qmenu, + .mmal_id = MMAL_PARAMETER_EXPOSURE_COMP, + .setter = ctrl_set_value_ev, }, { - V4L2_CID_EXPOSURE_AUTO_PRIORITY, MMAL_CONTROL_TYPE_STD, - 0, 1, - 0, 1, NULL, - 0, /* Dummy MMAL ID as it gets mapped into FPS range*/ - ctrl_set_exposure, - false + .id = V4L2_CID_EXPOSURE_AUTO_PRIORITY, + .type = MMAL_CONTROL_TYPE_STD, + .min = 0, + .max = 1, + .def = 0, + .step = 1, + .imenu = NULL, + /* Dummy MMAL ID as it gets mapped into FPS range */ + .mmal_id = 0, + .setter = ctrl_set_exposure, }, { - V4L2_CID_EXPOSURE_METERING, - MMAL_CONTROL_TYPE_STD_MENU, - ~0x7, V4L2_EXPOSURE_METERING_SPOT, - V4L2_EXPOSURE_METERING_AVERAGE, 0, NULL, - MMAL_PARAMETER_EXP_METERING_MODE, - ctrl_set_metering_mode, - false + .id = V4L2_CID_EXPOSURE_METERING, + .type = MMAL_CONTROL_TYPE_STD_MENU, + .min = ~0x7, + .max = V4L2_EXPOSURE_METERING_SPOT, + .def = V4L2_EXPOSURE_METERING_AVERAGE, + .step = 0, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_EXP_METERING_MODE, + .setter = ctrl_set_metering_mode, }, { - V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, - MMAL_CONTROL_TYPE_STD_MENU, - ~0x3ff, V4L2_WHITE_BALANCE_SHADE, V4L2_WHITE_BALANCE_AUTO, 0, - NULL, - MMAL_PARAMETER_AWB_MODE, - ctrl_set_awb_mode, - false + .id = V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, + .type = MMAL_CONTROL_TYPE_STD_MENU, + .min = ~0x3ff, + .max = V4L2_WHITE_BALANCE_SHADE, + .def = V4L2_WHITE_BALANCE_AUTO, + .step = 0, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_AWB_MODE, + .setter = ctrl_set_awb_mode, }, { - V4L2_CID_RED_BALANCE, MMAL_CONTROL_TYPE_STD, - 1, 7999, 1000, 1, NULL, - MMAL_PARAMETER_CUSTOM_AWB_GAINS, - ctrl_set_awb_gains, - false + .id = V4L2_CID_RED_BALANCE, + .type = MMAL_CONTROL_TYPE_STD, + .min = 1, + .max = 7999, + .def = 1000, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_CUSTOM_AWB_GAINS, + .setter = ctrl_set_awb_gains, }, { - V4L2_CID_BLUE_BALANCE, MMAL_CONTROL_TYPE_STD, - 1, 7999, 1000, 1, NULL, - MMAL_PARAMETER_CUSTOM_AWB_GAINS, - ctrl_set_awb_gains, - false + .id = V4L2_CID_BLUE_BALANCE, + .type = MMAL_CONTROL_TYPE_STD, + .min = 1, + .max = 7999, + .def = 1000, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_CUSTOM_AWB_GAINS, + .setter = ctrl_set_awb_gains, }, { - V4L2_CID_COLORFX, MMAL_CONTROL_TYPE_STD_MENU, - 0, V4L2_COLORFX_SET_CBCR, V4L2_COLORFX_NONE, 0, NULL, - MMAL_PARAMETER_IMAGE_EFFECT, - ctrl_set_image_effect, - false + .id = V4L2_CID_COLORFX, + .type = MMAL_CONTROL_TYPE_STD_MENU, + .min = 0, + .max = V4L2_COLORFX_SET_CBCR, + .def = V4L2_COLORFX_NONE, + .step = 0, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_IMAGE_EFFECT, + .setter = ctrl_set_image_effect, }, { - V4L2_CID_COLORFX_CBCR, MMAL_CONTROL_TYPE_STD, - 0, 0xffff, 0x8080, 1, NULL, - MMAL_PARAMETER_COLOUR_EFFECT, - ctrl_set_colfx, - false + .id = V4L2_CID_COLORFX_CBCR, + .type = MMAL_CONTROL_TYPE_STD, + .min = 0, + .max = 0xffff, + .def = 0x8080, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_COLOUR_EFFECT, + .setter = ctrl_set_colfx, }, { - V4L2_CID_ROTATE, MMAL_CONTROL_TYPE_STD, - 0, 360, 0, 90, NULL, - MMAL_PARAMETER_ROTATION, - ctrl_set_rotate, - false + .id = V4L2_CID_ROTATE, + .type = MMAL_CONTROL_TYPE_STD, + .min = 0, + .max = 360, + .def = 0, + .step = 90, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_ROTATION, + .setter = ctrl_set_rotate, }, { - V4L2_CID_HFLIP, MMAL_CONTROL_TYPE_STD, - 0, 1, 0, 1, NULL, - MMAL_PARAMETER_MIRROR, - ctrl_set_flip, - false + .id = V4L2_CID_HFLIP, + .type = MMAL_CONTROL_TYPE_STD, + .min = 0, + .max = 1, + .def = 0, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_MIRROR, + .setter = ctrl_set_flip, }, { - V4L2_CID_VFLIP, MMAL_CONTROL_TYPE_STD, - 0, 1, 0, 1, NULL, - MMAL_PARAMETER_MIRROR, - ctrl_set_flip, - false + .id = V4L2_CID_VFLIP, + .type = MMAL_CONTROL_TYPE_STD, + .min = 0, + .max = 1, + .def = 0, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_MIRROR, + .setter = ctrl_set_flip, }, { - V4L2_CID_MPEG_VIDEO_BITRATE_MODE, MMAL_CONTROL_TYPE_STD_MENU, - 0, V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, - 0, 0, NULL, - MMAL_PARAMETER_RATECONTROL, - ctrl_set_bitrate_mode, - false + .id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE, + .type = MMAL_CONTROL_TYPE_STD_MENU, + .min = 0, + .max = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, + .def = 0, + .step = 0, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_RATECONTROL, + .setter = ctrl_set_bitrate_mode, }, { - V4L2_CID_MPEG_VIDEO_BITRATE, MMAL_CONTROL_TYPE_STD, - 25 * 1000, 25 * 1000 * 1000, 10 * 1000 * 1000, 25 * 1000, NULL, - MMAL_PARAMETER_VIDEO_BIT_RATE, - ctrl_set_bitrate, - false + .id = V4L2_CID_MPEG_VIDEO_BITRATE, + .type = MMAL_CONTROL_TYPE_STD, + .min = 25 * 1000, + .max = 25 * 1000 * 1000, + .def = 10 * 1000 * 1000, + .step = 25 * 1000, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_VIDEO_BIT_RATE, + .setter = ctrl_set_bitrate, }, { - V4L2_CID_JPEG_COMPRESSION_QUALITY, MMAL_CONTROL_TYPE_STD, - 1, 100, - 30, 1, NULL, - MMAL_PARAMETER_JPEG_Q_FACTOR, - ctrl_set_image_encode_output, - false + .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, + .type = MMAL_CONTROL_TYPE_STD, + .min = 1, + .max = 100, + .def = 30, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_JPEG_Q_FACTOR, + .setter = ctrl_set_image_encode_output, }, { - V4L2_CID_POWER_LINE_FREQUENCY, MMAL_CONTROL_TYPE_STD_MENU, - 0, V4L2_CID_POWER_LINE_FREQUENCY_AUTO, - 1, 1, NULL, - MMAL_PARAMETER_FLICKER_AVOID, - ctrl_set_flicker_avoidance, - false + .id = V4L2_CID_POWER_LINE_FREQUENCY, + .type = MMAL_CONTROL_TYPE_STD_MENU, + .min = 0, + .max = V4L2_CID_POWER_LINE_FREQUENCY_AUTO, + .def = 1, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_FLICKER_AVOID, + .setter = ctrl_set_flicker_avoidance, }, { - V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, MMAL_CONTROL_TYPE_STD, - 0, 1, - 0, 1, NULL, - MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, - ctrl_set_video_encode_param_output, - false + .id = V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER, + .type = MMAL_CONTROL_TYPE_STD, + .min = 0, + .max = 1, + .def = 0, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, + .setter = ctrl_set_video_encode_param_output, }, { - V4L2_CID_MPEG_VIDEO_H264_PROFILE, - MMAL_CONTROL_TYPE_STD_MENU, - ~(BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | - BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, - V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, 1, NULL, - MMAL_PARAMETER_PROFILE, - ctrl_set_video_encode_profile_level, - false + .id = V4L2_CID_MPEG_VIDEO_H264_PROFILE, + .type = MMAL_CONTROL_TYPE_STD_MENU, + .min = ~(BIT(V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) | + BIT(V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)), + .max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .def = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_PROFILE, + .setter = ctrl_set_video_encode_profile_level, }, { - V4L2_CID_MPEG_VIDEO_H264_LEVEL, MMAL_CONTROL_TYPE_STD_MENU, - ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | - BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0)), - V4L2_MPEG_VIDEO_H264_LEVEL_4_0, - V4L2_MPEG_VIDEO_H264_LEVEL_4_0, 1, NULL, - MMAL_PARAMETER_PROFILE, - ctrl_set_video_encode_profile_level, - false + .id = V4L2_CID_MPEG_VIDEO_H264_LEVEL, + .type = MMAL_CONTROL_TYPE_STD_MENU, + .min = ~(BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1B) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_1_3) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_2_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | + BIT(V4L2_MPEG_VIDEO_H264_LEVEL_4_0)), + .max = V4L2_MPEG_VIDEO_H264_LEVEL_4_0, + .def = V4L2_MPEG_VIDEO_H264_LEVEL_4_0, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_PROFILE, + .setter = ctrl_set_video_encode_profile_level, }, { - V4L2_CID_SCENE_MODE, MMAL_CONTROL_TYPE_STD_MENU, - -1, /* Min (mask) is computed at runtime */ - V4L2_SCENE_MODE_TEXT, - V4L2_SCENE_MODE_NONE, 1, NULL, - MMAL_PARAMETER_PROFILE, - ctrl_set_scene_mode, - false + .id = V4L2_CID_SCENE_MODE, + .type = MMAL_CONTROL_TYPE_STD_MENU, + /* mask is computed at runtime */ + .min = -1, + .max = V4L2_SCENE_MODE_TEXT, + .def = V4L2_SCENE_MODE_NONE, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_PROFILE, + .setter = ctrl_set_scene_mode, }, { - V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, MMAL_CONTROL_TYPE_STD, - 0, 0x7FFFFFFF, 60, 1, NULL, - MMAL_PARAMETER_INTRAPERIOD, - ctrl_set_video_encode_param_output, - false + .id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD, + .type = MMAL_CONTROL_TYPE_STD, + .min = 0, + .max = 0x7FFFFFFF, + .def = 60, + .step = 1, + .imenu = NULL, + .mmal_id = MMAL_PARAMETER_INTRAPERIOD, + .setter = ctrl_set_video_encode_param_output, }, }; @@ -1168,7 +1266,7 @@ int bm2835_mmal_set_all_camera_controls(struct bm2835_mmal_dev *dev) if ((dev->ctrls[c]) && (v4l2_ctrls[c].setter)) { ret = v4l2_ctrls[c].setter(dev, dev->ctrls[c], &v4l2_ctrls[c]); - if (!v4l2_ctrls[c].ignore_errors && ret) { + if (ret) { v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "Failed when setting default values for ctrl %d\n", c); diff --git a/drivers/staging/vc04_services/interface/vchi/vchi_common.h b/drivers/staging/vc04_services/interface/vchi/vchi_common.h index 141af16ce031..7fc04e38936d 100644 --- a/drivers/staging/vc04_services/interface/vchi/vchi_common.h +++ b/drivers/staging/vc04_services/interface/vchi/vchi_common.h @@ -33,10 +33,14 @@ enum vchi_crc_control { enum vchi_callback_reason { VCHI_CALLBACK_REASON_MIN, - //This indicates that there is data available - //handle is the msg id that was transmitted with the data - // When a message is received and there was no FULL message available previously, send callback - // Tasks get kicked by the callback, reset their event and try and read from the fifo until it fails + /* + * This indicates that there is data available handle is the msg id that + * was transmitted with the data + * When a message is received and there was no FULL message available + * previously, send callback + * Tasks get kicked by the callback, reset their event and try and read + * from the fifo until it fails + */ VCHI_CALLBACK_MSG_AVAILABLE, VCHI_CALLBACK_MSG_SENT, VCHI_CALLBACK_MSG_SPACE_AVAILABLE, // XXX not yet implemented @@ -51,9 +55,11 @@ enum vchi_callback_reason { VCHI_CALLBACK_SERVICE_CLOSED, - // this side has sent XOFF to peer due to lack of data consumption by service - // (suggests the service may need to take some recovery action if it has - // been deliberately holding off consuming data) + /* + * this side has sent XOFF to peer due to lack of data consumption by + * service (suggests the service may need to take some recovery action + * if it has been deliberately holding off consuming data) + */ VCHI_CALLBACK_SENT_XOFF, VCHI_CALLBACK_SENT_XON, @@ -112,12 +118,16 @@ struct vchi_msg_vector { int32_t vec_len; }; -// Iterator structure for reading ahead through received message queue. Allocated by client, -// initialised by vchi_msg_look_ahead. Fields are for internal VCHI use only. -// Iterates over messages in queue at the instant of the call to vchi_msg_lookahead - -// will not proceed to messages received since. Behaviour is undefined if an iterator -// is used again after messages for that service are removed/dequeued by any -// means other than vchi_msg_iter_... calls on the iterator itself. +/* + * Iterator structure for reading ahead through received message queue. + * Allocated by client, initialised by vchi_msg_look_ahead. Fields are for + * internal VCHI use only. + * Iterates over messages in queue at the instant of the call to + * vchi_msg_lookahead - will not proceed to messages received since. + * Behaviour is undefined if an iterator is used again after messages for that + * service are removed/dequeued by any means other than vchi_msg_iter_... + * calls on the iterator itself. + */ struct vchi_msg_iter { struct opaque_vchi_service_t *service; void *last; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c index ca30bfd52919..c18c6ca0b6c0 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c @@ -257,49 +257,6 @@ int vchiq_dump_platform_state(void *dump_context) return vchiq_dump(dump_context, buf, len + 1); } -enum vchiq_status -vchiq_platform_suspend(struct vchiq_state *state) -{ - return VCHIQ_ERROR; -} - -enum vchiq_status -vchiq_platform_resume(struct vchiq_state *state) -{ - return VCHIQ_SUCCESS; -} - -void -vchiq_platform_paused(struct vchiq_state *state) -{ -} - -void -vchiq_platform_resumed(struct vchiq_state *state) -{ -} - -int -vchiq_platform_videocore_wanted(struct vchiq_state *state) -{ - return 1; // autosuspend not supported - videocore always wanted -} - -int -vchiq_platform_use_suspend_timer(void) -{ - return 0; -} -void -vchiq_dump_platform_use_state(struct vchiq_state *state) -{ - vchiq_log_info(vchiq_arm_log_level, "Suspend timer not in use"); -} -void -vchiq_platform_handle_timeout(struct vchiq_state *state) -{ - (void)state; -} /* * Local functions */ diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c index 4458c1e60fa3..a1ea9777a444 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c @@ -22,6 +22,7 @@ #include <linux/platform_device.h> #include <linux/compat.h> #include <linux/dma-mapping.h> +#include <linux/rcupdate.h> #include <soc/bcm2835/raspberrypi-firmware.h> #include "vchiq_core.h" @@ -48,39 +49,6 @@ int vchiq_arm_log_level = VCHIQ_LOG_DEFAULT; int vchiq_susp_log_level = VCHIQ_LOG_ERROR; -#define SUSPEND_TIMER_TIMEOUT_MS 100 -#define SUSPEND_RETRY_TIMER_TIMEOUT_MS 1000 - -#define VC_SUSPEND_NUM_OFFSET 3 /* number of values before idle which are -ve */ -static const char *const suspend_state_names[] = { - "VC_SUSPEND_FORCE_CANCELED", - "VC_SUSPEND_REJECTED", - "VC_SUSPEND_FAILED", - "VC_SUSPEND_IDLE", - "VC_SUSPEND_REQUESTED", - "VC_SUSPEND_IN_PROGRESS", - "VC_SUSPEND_SUSPENDED" -}; -#define VC_RESUME_NUM_OFFSET 1 /* number of values before idle which are -ve */ -static const char *const resume_state_names[] = { - "VC_RESUME_FAILED", - "VC_RESUME_IDLE", - "VC_RESUME_REQUESTED", - "VC_RESUME_IN_PROGRESS", - "VC_RESUME_RESUMED" -}; -/* The number of times we allow force suspend to timeout before actually -** _forcing_ suspend. This is to cater for SW which fails to release vchiq -** correctly - we don't want to prevent ARM suspend indefinitely in this case. -*/ -#define FORCE_SUSPEND_FAIL_MAX 8 - -/* The time in ms allowed for videocore to go idle when force suspend has been - * requested */ -#define FORCE_SUSPEND_TIMEOUT_MS 200 - -static void suspend_timer_callback(struct timer_list *t); - struct user_service { struct vchiq_service *service; void *userdata; @@ -2129,10 +2097,12 @@ int vchiq_dump_platform_instances(void *dump_context) /* There is no list of instances, so instead scan all services, marking those that have been dumped. */ + rcu_read_lock(); for (i = 0; i < state->unused_service; i++) { - struct vchiq_service *service = state->services[i]; + struct vchiq_service *service; struct vchiq_instance *instance; + service = rcu_dereference(state->services[i]); if (!service || service->base.callback != service_callback) continue; @@ -2140,18 +2110,26 @@ int vchiq_dump_platform_instances(void *dump_context) if (instance) instance->mark = 0; } + rcu_read_unlock(); for (i = 0; i < state->unused_service; i++) { - struct vchiq_service *service = state->services[i]; + struct vchiq_service *service; struct vchiq_instance *instance; int err; - if (!service || service->base.callback != service_callback) + rcu_read_lock(); + service = rcu_dereference(state->services[i]); + if (!service || service->base.callback != service_callback) { + rcu_read_unlock(); continue; + } instance = service->instance; - if (!instance || instance->mark) + if (!instance || instance->mark) { + rcu_read_unlock(); continue; + } + rcu_read_unlock(); len = snprintf(buf, sizeof(buf), "Instance %pK: pid %d,%s completions %d/%d", @@ -2161,7 +2139,6 @@ int vchiq_dump_platform_instances(void *dump_context) instance->completion_insert - instance->completion_remove, MAX_COMPLETIONS); - err = vchiq_dump(dump_context, buf, len + 1); if (err) return err; @@ -2184,17 +2161,17 @@ int vchiq_dump_platform_service_state(void *dump_context, char buf[80]; int len; - len = snprintf(buf, sizeof(buf), " instance %pK", service->instance); + len = scnprintf(buf, sizeof(buf), " instance %pK", service->instance); if ((service->base.callback == service_callback) && user_service->is_vchi) { - len += snprintf(buf + len, sizeof(buf) - len, + len += scnprintf(buf + len, sizeof(buf) - len, ", %d/%d messages", user_service->msg_insert - user_service->msg_remove, MSG_QUEUE_SIZE); if (user_service->dequeue_pending) - len += snprintf(buf + len, sizeof(buf) - len, + len += scnprintf(buf + len, sizeof(buf) - len, " (dequeue pending)"); } @@ -2258,27 +2235,6 @@ vchiq_fops = { * Autosuspend related functionality */ -int -vchiq_videocore_wanted(struct vchiq_state *state) -{ - struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); - - if (!arm_state) - /* autosuspend not supported - always return wanted */ - return 1; - else if (arm_state->blocked_count) - return 1; - else if (!arm_state->videocore_use_count) - /* usage count zero - check for override unless we're forcing */ - if (arm_state->resume_blocked) - return 0; - else - return vchiq_platform_videocore_wanted(state); - else - /* non-zero usage count - videocore still required */ - return 1; -} - static enum vchiq_status vchiq_keepalive_vchiq_callback(enum vchiq_reason reason, struct vchiq_header *header, @@ -2382,317 +2338,13 @@ vchiq_arm_init_state(struct vchiq_state *state, atomic_set(&arm_state->ka_use_ack_count, 0); atomic_set(&arm_state->ka_release_count, 0); - init_completion(&arm_state->vc_suspend_complete); - - init_completion(&arm_state->vc_resume_complete); - /* Initialise to 'done' state. We only want to block on resume - * completion while videocore is suspended. */ - set_resume_state(arm_state, VC_RESUME_RESUMED); - - init_completion(&arm_state->resume_blocker); - /* Initialise to 'done' state. We only want to block on this - * completion while resume is blocked */ - complete_all(&arm_state->resume_blocker); - - init_completion(&arm_state->blocked_blocker); - /* Initialise to 'done' state. We only want to block on this - * completion while things are waiting on the resume blocker */ - complete_all(&arm_state->blocked_blocker); - - arm_state->suspend_timer_timeout = SUSPEND_TIMER_TIMEOUT_MS; - arm_state->suspend_timer_running = 0; arm_state->state = state; - timer_setup(&arm_state->suspend_timer, suspend_timer_callback, - 0); - arm_state->first_connect = 0; } return VCHIQ_SUCCESS; } -/* -** Functions to modify the state variables; -** set_suspend_state -** set_resume_state -** -** There are more state variables than we might like, so ensure they remain in -** step. Suspend and resume state are maintained separately, since most of -** these state machines can operate independently. However, there are a few -** states where state transitions in one state machine cause a reset to the -** other state machine. In addition, there are some completion events which -** need to occur on state machine reset and end-state(s), so these are also -** dealt with in these functions. -** -** In all states we set the state variable according to the input, but in some -** cases we perform additional steps outlined below; -** -** VC_SUSPEND_IDLE - Initialise the suspend completion at the same time. -** The suspend completion is completed after any suspend -** attempt. When we reset the state machine we also reset -** the completion. This reset occurs when videocore is -** resumed, and also if we initiate suspend after a suspend -** failure. -** -** VC_SUSPEND_IN_PROGRESS - This state is considered the point of no return for -** suspend - ie from this point on we must try to suspend -** before resuming can occur. We therefore also reset the -** resume state machine to VC_RESUME_IDLE in this state. -** -** VC_SUSPEND_SUSPENDED - Suspend has completed successfully. Also call -** complete_all on the suspend completion to notify -** anything waiting for suspend to happen. -** -** VC_SUSPEND_REJECTED - Videocore rejected suspend. Videocore will also -** initiate resume, so no need to alter resume state. -** We call complete_all on the suspend completion to notify -** of suspend rejection. -** -** VC_SUSPEND_FAILED - We failed to initiate videocore suspend. We notify the -** suspend completion and reset the resume state machine. -** -** VC_RESUME_IDLE - Initialise the resume completion at the same time. The -** resume completion is in it's 'done' state whenever -** videcore is running. Therefore, the VC_RESUME_IDLE -** state implies that videocore is suspended. -** Hence, any thread which needs to wait until videocore is -** running can wait on this completion - it will only block -** if videocore is suspended. -** -** VC_RESUME_RESUMED - Resume has completed successfully. Videocore is running. -** Call complete_all on the resume completion to unblock -** any threads waiting for resume. Also reset the suspend -** state machine to it's idle state. -** -** VC_RESUME_FAILED - Currently unused - no mechanism to fail resume exists. -*/ - -void -set_suspend_state(struct vchiq_arm_state *arm_state, - enum vc_suspend_status new_state) -{ - /* set the state in all cases */ - arm_state->vc_suspend_state = new_state; - - /* state specific additional actions */ - switch (new_state) { - case VC_SUSPEND_FORCE_CANCELED: - complete_all(&arm_state->vc_suspend_complete); - break; - case VC_SUSPEND_REJECTED: - complete_all(&arm_state->vc_suspend_complete); - break; - case VC_SUSPEND_FAILED: - complete_all(&arm_state->vc_suspend_complete); - arm_state->vc_resume_state = VC_RESUME_RESUMED; - complete_all(&arm_state->vc_resume_complete); - break; - case VC_SUSPEND_IDLE: - reinit_completion(&arm_state->vc_suspend_complete); - break; - case VC_SUSPEND_REQUESTED: - break; - case VC_SUSPEND_IN_PROGRESS: - set_resume_state(arm_state, VC_RESUME_IDLE); - break; - case VC_SUSPEND_SUSPENDED: - complete_all(&arm_state->vc_suspend_complete); - break; - default: - BUG(); - break; - } -} - -void -set_resume_state(struct vchiq_arm_state *arm_state, - enum vc_resume_status new_state) -{ - /* set the state in all cases */ - arm_state->vc_resume_state = new_state; - - /* state specific additional actions */ - switch (new_state) { - case VC_RESUME_FAILED: - break; - case VC_RESUME_IDLE: - reinit_completion(&arm_state->vc_resume_complete); - break; - case VC_RESUME_REQUESTED: - break; - case VC_RESUME_IN_PROGRESS: - break; - case VC_RESUME_RESUMED: - complete_all(&arm_state->vc_resume_complete); - set_suspend_state(arm_state, VC_SUSPEND_IDLE); - break; - default: - BUG(); - break; - } -} - -/* should be called with the write lock held */ -inline void -start_suspend_timer(struct vchiq_arm_state *arm_state) -{ - del_timer(&arm_state->suspend_timer); - arm_state->suspend_timer.expires = jiffies + - msecs_to_jiffies(arm_state->suspend_timer_timeout); - add_timer(&arm_state->suspend_timer); - arm_state->suspend_timer_running = 1; -} - -/* should be called with the write lock held */ -static inline void -stop_suspend_timer(struct vchiq_arm_state *arm_state) -{ - if (arm_state->suspend_timer_running) { - del_timer(&arm_state->suspend_timer); - arm_state->suspend_timer_running = 0; - } -} - -static inline int -need_resume(struct vchiq_state *state) -{ - struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); - - return (arm_state->vc_suspend_state > VC_SUSPEND_IDLE) && - (arm_state->vc_resume_state < VC_RESUME_REQUESTED) && - vchiq_videocore_wanted(state); -} - -static inline void -unblock_resume(struct vchiq_arm_state *arm_state) -{ - complete_all(&arm_state->resume_blocker); - arm_state->resume_blocked = 0; -} - -/* Initiate suspend via slot handler. Should be called with the write lock - * held */ -enum vchiq_status -vchiq_arm_vcsuspend(struct vchiq_state *state) -{ - enum vchiq_status status = VCHIQ_ERROR; - struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); - - if (!arm_state) - goto out; - - vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); - status = VCHIQ_SUCCESS; - - switch (arm_state->vc_suspend_state) { - case VC_SUSPEND_REQUESTED: - vchiq_log_info(vchiq_susp_log_level, "%s: suspend already " - "requested", __func__); - break; - case VC_SUSPEND_IN_PROGRESS: - vchiq_log_info(vchiq_susp_log_level, "%s: suspend already in " - "progress", __func__); - break; - - default: - /* We don't expect to be in other states, so log but continue - * anyway */ - vchiq_log_error(vchiq_susp_log_level, - "%s unexpected suspend state %s", __func__, - suspend_state_names[arm_state->vc_suspend_state + - VC_SUSPEND_NUM_OFFSET]); - /* fall through */ - case VC_SUSPEND_REJECTED: - case VC_SUSPEND_FAILED: - /* Ensure any idle state actions have been run */ - set_suspend_state(arm_state, VC_SUSPEND_IDLE); - /* fall through */ - case VC_SUSPEND_IDLE: - vchiq_log_info(vchiq_susp_log_level, - "%s: suspending", __func__); - set_suspend_state(arm_state, VC_SUSPEND_REQUESTED); - /* kick the slot handler thread to initiate suspend */ - request_poll(state, NULL, 0); - break; - } - -out: - vchiq_log_trace(vchiq_susp_log_level, "%s exit %d", __func__, status); - return status; -} - -void -vchiq_platform_check_suspend(struct vchiq_state *state) -{ - struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); - int susp = 0; - - if (!arm_state) - goto out; - - vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); - - write_lock_bh(&arm_state->susp_res_lock); - if (arm_state->vc_suspend_state == VC_SUSPEND_REQUESTED && - arm_state->vc_resume_state == VC_RESUME_RESUMED) { - set_suspend_state(arm_state, VC_SUSPEND_IN_PROGRESS); - susp = 1; - } - write_unlock_bh(&arm_state->susp_res_lock); - - if (susp) - vchiq_platform_suspend(state); - -out: - vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__); - return; -} - -void -vchiq_check_suspend(struct vchiq_state *state) -{ - struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); - - if (!arm_state) - goto out; - - vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); - - write_lock_bh(&arm_state->susp_res_lock); - if (arm_state->vc_suspend_state != VC_SUSPEND_SUSPENDED && - arm_state->first_connect && - !vchiq_videocore_wanted(state)) { - vchiq_arm_vcsuspend(state); - } - write_unlock_bh(&arm_state->susp_res_lock); - -out: - vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__); -} - -/* This function should be called with the write lock held */ -int -vchiq_check_resume(struct vchiq_state *state) -{ - struct vchiq_arm_state *arm_state = vchiq_platform_get_arm_state(state); - int resume = 0; - - if (!arm_state) - goto out; - - vchiq_log_trace(vchiq_susp_log_level, "%s", __func__); - - if (need_resume(state)) { - set_resume_state(arm_state, VC_RESUME_REQUESTED); - request_poll(state, NULL, 0); - resume = 1; - } - -out: - vchiq_log_trace(vchiq_susp_log_level, "%s exit", __func__); - return resume; -} - enum vchiq_status vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service, enum USE_TYPE_E use_type) @@ -2724,88 +2376,15 @@ vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service, } write_lock_bh(&arm_state->susp_res_lock); - while (arm_state->resume_blocked) { - /* If we call 'use' while force suspend is waiting for suspend, - * then we're about to block the thread which the force is - * waiting to complete, so we're bound to just time out. In this - * case, set the suspend state such that the wait will be - * canceled, so we can complete as quickly as possible. */ - if (arm_state->resume_blocked && arm_state->vc_suspend_state == - VC_SUSPEND_IDLE) { - set_suspend_state(arm_state, VC_SUSPEND_FORCE_CANCELED); - break; - } - /* If suspend is already in progress then we need to block */ - if (!try_wait_for_completion(&arm_state->resume_blocker)) { - /* Indicate that there are threads waiting on the resume - * blocker. These need to be allowed to complete before - * a _second_ call to force suspend can complete, - * otherwise low priority threads might never actually - * continue */ - arm_state->blocked_count++; - write_unlock_bh(&arm_state->susp_res_lock); - vchiq_log_info(vchiq_susp_log_level, "%s %s resume " - "blocked - waiting...", __func__, entity); - if (wait_for_completion_killable( - &arm_state->resume_blocker)) { - vchiq_log_error(vchiq_susp_log_level, "%s %s " - "wait for resume blocker interrupted", - __func__, entity); - ret = VCHIQ_ERROR; - write_lock_bh(&arm_state->susp_res_lock); - arm_state->blocked_count--; - write_unlock_bh(&arm_state->susp_res_lock); - goto out; - } - vchiq_log_info(vchiq_susp_log_level, "%s %s resume " - "unblocked", __func__, entity); - write_lock_bh(&arm_state->susp_res_lock); - if (--arm_state->blocked_count == 0) - complete_all(&arm_state->blocked_blocker); - } - } - - stop_suspend_timer(arm_state); - local_uc = ++arm_state->videocore_use_count; local_entity_uc = ++(*entity_uc); - /* If there's a pending request which hasn't yet been serviced then - * just clear it. If we're past VC_SUSPEND_REQUESTED state then - * vc_resume_complete will block until we either resume or fail to - * suspend */ - if (arm_state->vc_suspend_state <= VC_SUSPEND_REQUESTED) - set_suspend_state(arm_state, VC_SUSPEND_IDLE); - - if ((use_type != USE_TYPE_SERVICE_NO_RESUME) && need_resume(state)) { - set_resume_state(arm_state, VC_RESUME_REQUESTED); - vchiq_log_info(vchiq_susp_log_level, - "%s %s count %d, state count %d", - __func__, entity, local_entity_uc, local_uc); - request_poll(state, NULL, 0); - } else - vchiq_log_trace(vchiq_susp_log_level, - "%s %s count %d, state count %d", - __func__, entity, *entity_uc, local_uc); + vchiq_log_trace(vchiq_susp_log_level, + "%s %s count %d, state count %d", + __func__, entity, *entity_uc, local_uc); write_unlock_bh(&arm_state->susp_res_lock); - /* Completion is in a done state when we're not suspended, so this won't - * block for the non-suspended case. */ - if (!try_wait_for_completion(&arm_state->vc_resume_complete)) { - vchiq_log_info(vchiq_susp_log_level, "%s %s wait for resume", - __func__, entity); - if (wait_for_completion_killable( - &arm_state->vc_resume_complete)) { - vchiq_log_error(vchiq_susp_log_level, "%s %s wait for " - "resume interrupted", __func__, entity); - ret = VCHIQ_ERROR; - goto out; - } - vchiq_log_info(vchiq_susp_log_level, "%s %s resumed", __func__, - entity); - } - if (ret == VCHIQ_SUCCESS) { enum vchiq_status status = VCHIQ_SUCCESS; long ack_cnt = atomic_xchg(&arm_state->ka_use_ack_count, 0); @@ -2860,24 +2439,10 @@ vchiq_release_internal(struct vchiq_state *state, struct vchiq_service *service) --arm_state->videocore_use_count; --(*entity_uc); - if (!vchiq_videocore_wanted(state)) { - if (vchiq_platform_use_suspend_timer() && - !arm_state->resume_blocked) { - /* Only use the timer if we're not trying to force - * suspend (=> resume_blocked) */ - start_suspend_timer(arm_state); - } else { - vchiq_log_info(vchiq_susp_log_level, - "%s %s count %d, state count %d - suspending", - __func__, entity, *entity_uc, - arm_state->videocore_use_count); - vchiq_arm_vcsuspend(state); - } - } else - vchiq_log_trace(vchiq_susp_log_level, - "%s %s count %d, state count %d", - __func__, entity, *entity_uc, - arm_state->videocore_use_count); + vchiq_log_trace(vchiq_susp_log_level, + "%s %s count %d, state count %d", + __func__, entity, *entity_uc, + arm_state->videocore_use_count); unlock: write_unlock_bh(&arm_state->susp_res_lock); @@ -2932,11 +2497,11 @@ vchiq_instance_get_use_count(struct vchiq_instance *instance) int use_count = 0, i; i = 0; - while ((service = next_service_by_instance(instance->state, - instance, &i))) { + rcu_read_lock(); + while ((service = __next_service_by_instance(instance->state, + instance, &i))) use_count += service->service_use_count; - unlock_service(service); - } + rcu_read_unlock(); return use_count; } @@ -2959,25 +2524,14 @@ vchiq_instance_set_trace(struct vchiq_instance *instance, int trace) int i; i = 0; - while ((service = next_service_by_instance(instance->state, - instance, &i))) { + rcu_read_lock(); + while ((service = __next_service_by_instance(instance->state, + instance, &i))) service->trace = trace; - unlock_service(service); - } + rcu_read_unlock(); instance->trace = (trace != 0); } -static void suspend_timer_callback(struct timer_list *t) -{ - struct vchiq_arm_state *arm_state = - from_timer(arm_state, t, suspend_timer); - struct vchiq_state *state = arm_state->state; - - vchiq_log_info(vchiq_susp_log_level, - "%s - suspend timer expired - check suspend", __func__); - vchiq_check_suspend(state); -} - enum vchiq_status vchiq_use_service(unsigned int handle) { @@ -3022,8 +2576,6 @@ vchiq_dump_service_use_state(struct vchiq_state *state) int only_nonzero = 0; static const char *nz = "<-- preventing suspend"; - enum vc_suspend_status vc_suspend_state; - enum vc_resume_status vc_resume_state; int peer_count; int vc_use_count; int active_services; @@ -3037,16 +2589,16 @@ vchiq_dump_service_use_state(struct vchiq_state *state) return; read_lock_bh(&arm_state->susp_res_lock); - vc_suspend_state = arm_state->vc_suspend_state; - vc_resume_state = arm_state->vc_resume_state; peer_count = arm_state->peer_use_count; vc_use_count = arm_state->videocore_use_count; active_services = state->unused_service; if (active_services > MAX_SERVICES) only_nonzero = 1; + rcu_read_lock(); for (i = 0; i < active_services; i++) { - struct vchiq_service *service_ptr = state->services[i]; + struct vchiq_service *service_ptr = + rcu_dereference(state->services[i]); if (!service_ptr) continue; @@ -3064,16 +2616,10 @@ vchiq_dump_service_use_state(struct vchiq_state *state) if (found >= MAX_SERVICES) break; } + rcu_read_unlock(); read_unlock_bh(&arm_state->susp_res_lock); - vchiq_log_warning(vchiq_susp_log_level, - "-- Videcore suspend state: %s --", - suspend_state_names[vc_suspend_state + VC_SUSPEND_NUM_OFFSET]); - vchiq_log_warning(vchiq_susp_log_level, - "-- Videcore resume state: %s --", - resume_state_names[vc_resume_state + VC_RESUME_NUM_OFFSET]); - if (only_nonzero) vchiq_log_warning(vchiq_susp_log_level, "Too many active " "services (%d). Only dumping up to first %d services " @@ -3093,8 +2639,6 @@ vchiq_dump_service_use_state(struct vchiq_state *state) "--- Overall vchiq instance use count %d", vc_use_count); kfree(service_data); - - vchiq_dump_platform_use_state(state); } enum vchiq_status @@ -3118,24 +2662,16 @@ vchiq_check_service(struct vchiq_service *service) if (ret == VCHIQ_ERROR) { vchiq_log_error(vchiq_susp_log_level, "%s ERROR - %c%c%c%c:%d service count %d, " - "state count %d, videocore suspend state %s", __func__, + "state count %d", __func__, VCHIQ_FOURCC_AS_4CHARS(service->base.fourcc), service->client_id, service->service_use_count, - arm_state->videocore_use_count, - suspend_state_names[arm_state->vc_suspend_state + - VC_SUSPEND_NUM_OFFSET]); + arm_state->videocore_use_count); vchiq_dump_service_use_state(service->state); } out: return ret; } -/* stub functions */ -void vchiq_on_remote_use_active(struct vchiq_state *state) -{ - (void)state; -} - void vchiq_platform_conn_state_changed(struct vchiq_state *state, enum vchiq_connstate oldstate, enum vchiq_connstate newstate) diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h index 19d2a2eefb6a..0784c5002417 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.h @@ -14,27 +14,8 @@ #include "vchiq_core.h" #include "vchiq_debugfs.h" -enum vc_suspend_status { - VC_SUSPEND_FORCE_CANCELED = -3, /* Force suspend canceled, too busy */ - VC_SUSPEND_REJECTED = -2, /* Videocore rejected suspend request */ - VC_SUSPEND_FAILED = -1, /* Videocore suspend failed */ - VC_SUSPEND_IDLE = 0, /* VC active, no suspend actions */ - VC_SUSPEND_REQUESTED, /* User has requested suspend */ - VC_SUSPEND_IN_PROGRESS, /* Slot handler has recvd suspend request */ - VC_SUSPEND_SUSPENDED /* Videocore suspend succeeded */ -}; - -enum vc_resume_status { - VC_RESUME_FAILED = -1, /* Videocore resume failed */ - VC_RESUME_IDLE = 0, /* VC suspended, no resume actions */ - VC_RESUME_REQUESTED, /* User has requested resume */ - VC_RESUME_IN_PROGRESS, /* Slot handler has received resume request */ - VC_RESUME_RESUMED /* Videocore resumed successfully (active) */ -}; - enum USE_TYPE_E { USE_TYPE_SERVICE, - USE_TYPE_SERVICE_NO_RESUME, USE_TYPE_VCHIQ }; @@ -46,19 +27,9 @@ struct vchiq_arm_state { atomic_t ka_use_ack_count; atomic_t ka_release_count; - struct completion vc_suspend_complete; - struct completion vc_resume_complete; - rwlock_t susp_res_lock; - enum vc_suspend_status vc_suspend_state; - enum vc_resume_status vc_resume_state; - - unsigned int wake_address; struct vchiq_state *state; - struct timer_list suspend_timer; - int suspend_timer_timeout; - int suspend_timer_running; /* Global use count for videocore. ** This is equal to the sum of the use counts for all services. When @@ -72,27 +43,11 @@ struct vchiq_arm_state { */ int peer_use_count; - /* Flag to indicate whether resume is blocked. This happens when the - ** ARM is suspending - */ - struct completion resume_blocker; - int resume_blocked; - struct completion blocked_blocker; - int blocked_count; - - int autosuspend_override; - /* Flag to indicate that the first vchiq connect has made it through. ** This means that both sides should be fully ready, and we should ** be able to suspend after this point. */ int first_connect; - - unsigned long long suspend_start_time; - unsigned long long sleep_start_time; - unsigned long long resume_start_time; - unsigned long long last_wake_time; - }; struct vchiq_drvdata { @@ -110,18 +65,9 @@ extern struct vchiq_state * vchiq_get_state(void); extern enum vchiq_status -vchiq_arm_vcsuspend(struct vchiq_state *state); - -extern enum vchiq_status -vchiq_arm_vcresume(struct vchiq_state *state); - -extern enum vchiq_status vchiq_arm_init_state(struct vchiq_state *state, struct vchiq_arm_state *arm_state); -extern int -vchiq_check_resume(struct vchiq_state *state); - extern void vchiq_check_suspend(struct vchiq_state *state); enum vchiq_status @@ -133,15 +79,6 @@ vchiq_release_service(unsigned int handle); extern enum vchiq_status vchiq_check_service(struct vchiq_service *service); -extern enum vchiq_status -vchiq_platform_suspend(struct vchiq_state *state); - -extern int -vchiq_platform_videocore_wanted(struct vchiq_state *state); - -extern int -vchiq_platform_use_suspend_timer(void); - extern void vchiq_dump_platform_use_state(struct vchiq_state *state); @@ -151,8 +88,6 @@ vchiq_dump_service_use_state(struct vchiq_state *state); extern struct vchiq_arm_state* vchiq_platform_get_arm_state(struct vchiq_state *state); -extern int -vchiq_videocore_wanted(struct vchiq_state *state); extern enum vchiq_status vchiq_use_internal(struct vchiq_state *state, struct vchiq_service *service, @@ -176,15 +111,4 @@ vchiq_instance_get_trace(struct vchiq_instance *instance); extern void vchiq_instance_set_trace(struct vchiq_instance *instance, int trace); -extern void -set_suspend_state(struct vchiq_arm_state *arm_state, - enum vc_suspend_status new_state); - -extern void -set_resume_state(struct vchiq_arm_state *arm_state, - enum vc_resume_status new_state); - -extern void -start_suspend_timer(struct vchiq_arm_state *arm_state); - #endif /* VCHIQ_ARM_H */ diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c index 76351078affb..edcd97373809 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.c @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* Copyright (c) 2010-2012 Broadcom. All rights reserved. */ +#include <linux/kref.h> +#include <linux/rcupdate.h> + #include "vchiq_core.h" #define VCHIQ_SLOT_HANDLER_STACK 8192 @@ -54,7 +57,6 @@ int vchiq_core_log_level = VCHIQ_LOG_DEFAULT; int vchiq_core_msg_log_level = VCHIQ_LOG_DEFAULT; int vchiq_sync_log_level = VCHIQ_LOG_DEFAULT; -static DEFINE_SPINLOCK(service_spinlock); DEFINE_SPINLOCK(bulk_waiter_spinlock); static DEFINE_SPINLOCK(quota_spinlock); @@ -136,44 +138,41 @@ find_service_by_handle(unsigned int handle) { struct vchiq_service *service; - spin_lock(&service_spinlock); + rcu_read_lock(); service = handle_to_service(handle); - if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) && - (service->handle == handle)) { - WARN_ON(service->ref_count == 0); - service->ref_count++; - } else - service = NULL; - spin_unlock(&service_spinlock); - - if (!service) - vchiq_log_info(vchiq_core_log_level, - "Invalid service handle 0x%x", handle); - - return service; + if (service && service->srvstate != VCHIQ_SRVSTATE_FREE && + service->handle == handle && + kref_get_unless_zero(&service->ref_count)) { + service = rcu_pointer_handoff(service); + rcu_read_unlock(); + return service; + } + rcu_read_unlock(); + vchiq_log_info(vchiq_core_log_level, + "Invalid service handle 0x%x", handle); + return NULL; } struct vchiq_service * find_service_by_port(struct vchiq_state *state, int localport) { - struct vchiq_service *service = NULL; if ((unsigned int)localport <= VCHIQ_PORT_MAX) { - spin_lock(&service_spinlock); - service = state->services[localport]; - if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE)) { - WARN_ON(service->ref_count == 0); - service->ref_count++; - } else - service = NULL; - spin_unlock(&service_spinlock); - } - - if (!service) - vchiq_log_info(vchiq_core_log_level, - "Invalid port %d", localport); + struct vchiq_service *service; - return service; + rcu_read_lock(); + service = rcu_dereference(state->services[localport]); + if (service && service->srvstate != VCHIQ_SRVSTATE_FREE && + kref_get_unless_zero(&service->ref_count)) { + service = rcu_pointer_handoff(service); + rcu_read_unlock(); + return service; + } + rcu_read_unlock(); + } + vchiq_log_info(vchiq_core_log_level, + "Invalid port %d", localport); + return NULL; } struct vchiq_service * @@ -182,22 +181,20 @@ find_service_for_instance(struct vchiq_instance *instance, { struct vchiq_service *service; - spin_lock(&service_spinlock); + rcu_read_lock(); service = handle_to_service(handle); - if (service && (service->srvstate != VCHIQ_SRVSTATE_FREE) && - (service->handle == handle) && - (service->instance == instance)) { - WARN_ON(service->ref_count == 0); - service->ref_count++; - } else - service = NULL; - spin_unlock(&service_spinlock); - - if (!service) - vchiq_log_info(vchiq_core_log_level, - "Invalid service handle 0x%x", handle); - - return service; + if (service && service->srvstate != VCHIQ_SRVSTATE_FREE && + service->handle == handle && + service->instance == instance && + kref_get_unless_zero(&service->ref_count)) { + service = rcu_pointer_handoff(service); + rcu_read_unlock(); + return service; + } + rcu_read_unlock(); + vchiq_log_info(vchiq_core_log_level, + "Invalid service handle 0x%x", handle); + return NULL; } struct vchiq_service * @@ -206,121 +203,125 @@ find_closed_service_for_instance(struct vchiq_instance *instance, { struct vchiq_service *service; - spin_lock(&service_spinlock); + rcu_read_lock(); service = handle_to_service(handle); if (service && - ((service->srvstate == VCHIQ_SRVSTATE_FREE) || - (service->srvstate == VCHIQ_SRVSTATE_CLOSED)) && - (service->handle == handle) && - (service->instance == instance)) { - WARN_ON(service->ref_count == 0); - service->ref_count++; - } else - service = NULL; - spin_unlock(&service_spinlock); - - if (!service) - vchiq_log_info(vchiq_core_log_level, - "Invalid service handle 0x%x", handle); - + (service->srvstate == VCHIQ_SRVSTATE_FREE || + service->srvstate == VCHIQ_SRVSTATE_CLOSED) && + service->handle == handle && + service->instance == instance && + kref_get_unless_zero(&service->ref_count)) { + service = rcu_pointer_handoff(service); + rcu_read_unlock(); + return service; + } + rcu_read_unlock(); + vchiq_log_info(vchiq_core_log_level, + "Invalid service handle 0x%x", handle); return service; } struct vchiq_service * -next_service_by_instance(struct vchiq_state *state, struct vchiq_instance *instance, - int *pidx) +__next_service_by_instance(struct vchiq_state *state, + struct vchiq_instance *instance, + int *pidx) { struct vchiq_service *service = NULL; int idx = *pidx; - spin_lock(&service_spinlock); while (idx < state->unused_service) { - struct vchiq_service *srv = state->services[idx++]; + struct vchiq_service *srv; - if (srv && (srv->srvstate != VCHIQ_SRVSTATE_FREE) && - (srv->instance == instance)) { + srv = rcu_dereference(state->services[idx++]); + if (srv && srv->srvstate != VCHIQ_SRVSTATE_FREE && + srv->instance == instance) { service = srv; - WARN_ON(service->ref_count == 0); - service->ref_count++; break; } } - spin_unlock(&service_spinlock); *pidx = idx; + return service; +} + +struct vchiq_service * +next_service_by_instance(struct vchiq_state *state, + struct vchiq_instance *instance, + int *pidx) +{ + struct vchiq_service *service; + rcu_read_lock(); + while (1) { + service = __next_service_by_instance(state, instance, pidx); + if (!service) + break; + if (kref_get_unless_zero(&service->ref_count)) { + service = rcu_pointer_handoff(service); + break; + } + } + rcu_read_unlock(); return service; } void lock_service(struct vchiq_service *service) { - spin_lock(&service_spinlock); - WARN_ON(!service); - if (service) { - WARN_ON(service->ref_count == 0); - service->ref_count++; + if (!service) { + WARN(1, "%s service is NULL\n", __func__); + return; } - spin_unlock(&service_spinlock); + kref_get(&service->ref_count); +} + +static void service_release(struct kref *kref) +{ + struct vchiq_service *service = + container_of(kref, struct vchiq_service, ref_count); + struct vchiq_state *state = service->state; + + WARN_ON(service->srvstate != VCHIQ_SRVSTATE_FREE); + rcu_assign_pointer(state->services[service->localport], NULL); + if (service->userdata_term) + service->userdata_term(service->base.userdata); + kfree_rcu(service, rcu); } void unlock_service(struct vchiq_service *service) { - spin_lock(&service_spinlock); if (!service) { WARN(1, "%s: service is NULL\n", __func__); - goto unlock; - } - if (!service->ref_count) { - WARN(1, "%s: ref_count is zero\n", __func__); - goto unlock; - } - service->ref_count--; - if (!service->ref_count) { - struct vchiq_state *state = service->state; - - WARN_ON(service->srvstate != VCHIQ_SRVSTATE_FREE); - state->services[service->localport] = NULL; - } else { - service = NULL; + return; } -unlock: - spin_unlock(&service_spinlock); - - if (service && service->userdata_term) - service->userdata_term(service->base.userdata); - - kfree(service); + kref_put(&service->ref_count, service_release); } int vchiq_get_client_id(unsigned int handle) { - struct vchiq_service *service = find_service_by_handle(handle); + struct vchiq_service *service; int id; + rcu_read_lock(); + service = handle_to_service(handle); id = service ? service->client_id : 0; - if (service) - unlock_service(service); - + rcu_read_unlock(); return id; } void * vchiq_get_service_userdata(unsigned int handle) { - struct vchiq_service *service = handle_to_service(handle); - - return service ? service->base.userdata : NULL; -} - -int -vchiq_get_service_fourcc(unsigned int handle) -{ - struct vchiq_service *service = handle_to_service(handle); + void *userdata; + struct vchiq_service *service; - return service ? service->base.fourcc : 0; + rcu_read_lock(); + service = handle_to_service(handle); + userdata = service ? service->base.userdata : NULL; + rcu_read_unlock(); + return userdata; } static void @@ -468,19 +469,23 @@ get_listening_service(struct vchiq_state *state, int fourcc) WARN_ON(fourcc == VCHIQ_FOURCC_INVALID); + rcu_read_lock(); for (i = 0; i < state->unused_service; i++) { - struct vchiq_service *service = state->services[i]; + struct vchiq_service *service; + service = rcu_dereference(state->services[i]); if (service && - (service->public_fourcc == fourcc) && - ((service->srvstate == VCHIQ_SRVSTATE_LISTENING) || - ((service->srvstate == VCHIQ_SRVSTATE_OPEN) && - (service->remoteport == VCHIQ_PORT_FREE)))) { - lock_service(service); + service->public_fourcc == fourcc && + (service->srvstate == VCHIQ_SRVSTATE_LISTENING || + (service->srvstate == VCHIQ_SRVSTATE_OPEN && + service->remoteport == VCHIQ_PORT_FREE)) && + kref_get_unless_zero(&service->ref_count)) { + service = rcu_pointer_handoff(service); + rcu_read_unlock(); return service; } } - + rcu_read_unlock(); return NULL; } @@ -490,15 +495,20 @@ get_connected_service(struct vchiq_state *state, unsigned int port) { int i; + rcu_read_lock(); for (i = 0; i < state->unused_service; i++) { - struct vchiq_service *service = state->services[i]; - - if (service && (service->srvstate == VCHIQ_SRVSTATE_OPEN) - && (service->remoteport == port)) { - lock_service(service); + struct vchiq_service *service = + rcu_dereference(state->services[i]); + + if (service && service->srvstate == VCHIQ_SRVSTATE_OPEN && + service->remoteport == port && + kref_get_unless_zero(&service->ref_count)) { + service = rcu_pointer_handoff(service); + rcu_read_unlock(); return service; } } + rcu_read_unlock(); return NULL; } @@ -1798,7 +1808,6 @@ parse_rx_slots(struct vchiq_state *state) } /* At this point slot_mutex is held */ vchiq_set_conn_state(state, VCHIQ_CONNSTATE_PAUSED); - vchiq_platform_paused(state); break; case VCHIQ_MSG_RESUME: vchiq_log_trace(vchiq_core_log_level, @@ -1807,7 +1816,6 @@ parse_rx_slots(struct vchiq_state *state) /* Release the slot mutex */ mutex_unlock(&state->slot_mutex); vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED); - vchiq_platform_resumed(state); break; case VCHIQ_MSG_REMOTE_USE: @@ -1817,7 +1825,6 @@ parse_rx_slots(struct vchiq_state *state) vchiq_on_remote_release(state); break; case VCHIQ_MSG_REMOTE_USE_ACTIVE: - vchiq_on_remote_use_active(state); break; default: @@ -1869,9 +1876,6 @@ slot_handler_func(void *v) DEBUG_TRACE(SLOT_HANDLER_LINE); if (state->poll_needed) { - /* Check if we need to suspend - may change our - * conn_state */ - vchiq_platform_check_suspend(state); state->poll_needed = 0; @@ -1897,10 +1901,6 @@ slot_handler_func(void *v) } break; - case VCHIQ_CONNSTATE_PAUSED: - vchiq_platform_resume(state); - break; - case VCHIQ_CONNSTATE_RESUMING: if (queue_message(state, NULL, VCHIQ_MAKE_MSG(VCHIQ_MSG_RESUME, 0, 0), @@ -1908,7 +1908,6 @@ slot_handler_func(void *v) != VCHIQ_RETRY) { vchiq_set_conn_state(state, VCHIQ_CONNSTATE_CONNECTED); - vchiq_platform_resumed(state); } else { /* This should really be impossible, ** since the PAUSE should have flushed @@ -1918,11 +1917,6 @@ slot_handler_func(void *v) "message"); } break; - - case VCHIQ_CONNSTATE_PAUSE_TIMEOUT: - case VCHIQ_CONNSTATE_RESUME_TIMEOUT: - vchiq_platform_handle_timeout(state); - break; default: break; } @@ -2284,7 +2278,7 @@ vchiq_add_service_internal(struct vchiq_state *state, vchiq_userdata_term userdata_term) { struct vchiq_service *service; - struct vchiq_service **pservice = NULL; + struct vchiq_service __rcu **pservice = NULL; struct vchiq_service_quota *service_quota; int i; @@ -2296,7 +2290,7 @@ vchiq_add_service_internal(struct vchiq_state *state, service->base.callback = params->callback; service->base.userdata = params->userdata; service->handle = VCHIQ_SERVICE_HANDLE_INVALID; - service->ref_count = 1; + kref_init(&service->ref_count); service->srvstate = VCHIQ_SRVSTATE_FREE; service->userdata_term = userdata_term; service->localport = VCHIQ_PORT_FREE; @@ -2322,7 +2316,7 @@ vchiq_add_service_internal(struct vchiq_state *state, mutex_init(&service->bulk_mutex); memset(&service->stats, 0, sizeof(service->stats)); - /* Although it is perfectly possible to use service_spinlock + /* Although it is perfectly possible to use a spinlock ** to protect the creation of services, it is overkill as it ** disables interrupts while the array is searched. ** The only danger is of another thread trying to create a @@ -2340,17 +2334,17 @@ vchiq_add_service_internal(struct vchiq_state *state, if (srvstate == VCHIQ_SRVSTATE_OPENING) { for (i = 0; i < state->unused_service; i++) { - struct vchiq_service *srv = state->services[i]; - - if (!srv) { + if (!rcu_access_pointer(state->services[i])) { pservice = &state->services[i]; break; } } } else { + rcu_read_lock(); for (i = (state->unused_service - 1); i >= 0; i--) { - struct vchiq_service *srv = state->services[i]; + struct vchiq_service *srv; + srv = rcu_dereference(state->services[i]); if (!srv) pservice = &state->services[i]; else if ((srv->public_fourcc == params->fourcc) @@ -2363,6 +2357,7 @@ vchiq_add_service_internal(struct vchiq_state *state, break; } } + rcu_read_unlock(); } if (pservice) { @@ -2374,7 +2369,7 @@ vchiq_add_service_internal(struct vchiq_state *state, (state->id * VCHIQ_MAX_SERVICES) | service->localport; handle_seq += VCHIQ_MAX_STATES * VCHIQ_MAX_SERVICES; - *pservice = service; + rcu_assign_pointer(*pservice, service); if (pservice == &state->services[state->unused_service]) state->unused_service++; } @@ -2437,13 +2432,13 @@ vchiq_open_service_internal(struct vchiq_service *service, int client_id) status = VCHIQ_RETRY; vchiq_release_service_internal(service); } else if ((service->srvstate != VCHIQ_SRVSTATE_OPEN) && - (service->srvstate != VCHIQ_SRVSTATE_OPENSYNC)) { + (service->srvstate != VCHIQ_SRVSTATE_OPENSYNC)) { if (service->srvstate != VCHIQ_SRVSTATE_CLOSEWAIT) vchiq_log_error(vchiq_core_log_level, - "%d: osi - srvstate = %s (ref %d)", - service->state->id, - srvstate_names[service->srvstate], - service->ref_count); + "%d: osi - srvstate = %s (ref %u)", + service->state->id, + srvstate_names[service->srvstate], + kref_read(&service->ref_count)); status = VCHIQ_ERROR; VCHIQ_SERVICE_STATS_INC(service, error_count); vchiq_release_service_internal(service); @@ -3449,10 +3444,13 @@ int vchiq_dump_service_state(void *dump_context, struct vchiq_service *service) char buf[80]; int len; int err; + unsigned int ref_count; + /*Don't include the lock just taken*/ + ref_count = kref_read(&service->ref_count) - 1; len = scnprintf(buf, sizeof(buf), "Service %u: %s (ref %u)", - service->localport, srvstate_names[service->srvstate], - service->ref_count - 1); /*Don't include the lock just taken*/ + service->localport, srvstate_names[service->srvstate], + ref_count); if (service->srvstate != VCHIQ_SRVSTATE_FREE) { char remoteport[30]; diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h index c31f953a9986..cedd8e721aae 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_core.h @@ -7,6 +7,8 @@ #include <linux/mutex.h> #include <linux/completion.h> #include <linux/kthread.h> +#include <linux/kref.h> +#include <linux/rcupdate.h> #include <linux/wait.h> #include "vchiq_cfg.h" @@ -251,7 +253,8 @@ struct vchiq_slot_info { struct vchiq_service { struct vchiq_service_base base; unsigned int handle; - unsigned int ref_count; + struct kref ref_count; + struct rcu_head rcu; int srvstate; vchiq_userdata_term userdata_term; unsigned int localport; @@ -464,7 +467,7 @@ struct vchiq_state { int error_count; } stats; - struct vchiq_service *services[VCHIQ_MAX_SERVICES]; + struct vchiq_service __rcu *services[VCHIQ_MAX_SERVICES]; struct vchiq_service_quota service_quotas[VCHIQ_MAX_SERVICES]; struct vchiq_slot_info slot_info[VCHIQ_MAX_SLOTS]; @@ -545,12 +548,13 @@ request_poll(struct vchiq_state *state, struct vchiq_service *service, static inline struct vchiq_service * handle_to_service(unsigned int handle) { + int idx = handle & (VCHIQ_MAX_SERVICES - 1); struct vchiq_state *state = vchiq_states[(handle / VCHIQ_MAX_SERVICES) & (VCHIQ_MAX_STATES - 1)]; + if (!state) return NULL; - - return state->services[handle & (VCHIQ_MAX_SERVICES - 1)]; + return rcu_dereference(state->services[idx]); } extern struct vchiq_service * @@ -568,7 +572,13 @@ find_closed_service_for_instance(struct vchiq_instance *instance, unsigned int handle); extern struct vchiq_service * -next_service_by_instance(struct vchiq_state *state, struct vchiq_instance *instance, +__next_service_by_instance(struct vchiq_state *state, + struct vchiq_instance *instance, + int *pidx); + +extern struct vchiq_service * +next_service_by_instance(struct vchiq_state *state, + struct vchiq_instance *instance, int *pidx); extern void @@ -590,18 +600,6 @@ vchiq_complete_bulk(struct vchiq_bulk *bulk); extern void remote_event_signal(struct remote_event *event); -void -vchiq_platform_check_suspend(struct vchiq_state *state); - -extern void -vchiq_platform_paused(struct vchiq_state *state); - -extern enum vchiq_status -vchiq_platform_resume(struct vchiq_state *state); - -extern void -vchiq_platform_resumed(struct vchiq_state *state); - extern int vchiq_dump(void *dump_context, const char *str, int len); @@ -648,9 +646,6 @@ vchiq_platform_conn_state_changed(struct vchiq_state *state, enum vchiq_connstate newstate); extern void -vchiq_platform_handle_timeout(struct vchiq_state *state); - -extern void vchiq_set_conn_state(struct vchiq_state *state, enum vchiq_connstate newstate); extern void diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h index 07c6a3db5ab6..39b77ea19210 100644 --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_if.h @@ -13,7 +13,6 @@ #define VCHIQ_MAKE_FOURCC(x0, x1, x2, x3) \ (((x0) << 24) | ((x1) << 16) | ((x2) << 8) | (x3)) #define VCHIQ_GET_SERVICE_USERDATA(service) vchiq_get_service_userdata(service) -#define VCHIQ_GET_SERVICE_FOURCC(service) vchiq_get_service_fourcc(service) enum vchiq_reason { VCHIQ_SERVICE_OPENED, /* service, -, - */ @@ -128,7 +127,6 @@ extern enum vchiq_status vchiq_bulk_receive_handle(unsigned int service, enum vchiq_bulk_mode mode); extern int vchiq_get_client_id(unsigned int service); extern void *vchiq_get_service_userdata(unsigned int service); -extern int vchiq_get_service_fourcc(unsigned int service); extern void vchiq_get_config(struct vchiq_config *config); extern enum vchiq_status vchiq_set_service_option(unsigned int service, enum vchiq_service_option option, int value); |