From 768248256339da88d65088c8beffe1a3dcd9f1ca Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 17 Jun 2009 17:17:18 +0200 Subject: ALSA: hda - Add description about patch loading Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 88b7433d2f1..8bc9867c0a3 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -403,6 +403,52 @@ re-configure based on that state, run like below: ------------------------------------------------------------------------ +Early Patching +~~~~~~~~~~~~~~ +When CONFIG_SND_HDA_PATCH_LOADER=y is set, you can pass a "patch" as a +firmware file for modifying the HD-audio setup before initializing the +codec. This can work basically like the reconfiguration via sysfs in +the above, but it does it before the first codec configuration. + +The patch file looks like below: + +------------------------------------------------------------------------ + [codec] + 0x12345678 0xabcd1234 2 + + [model] + auto + + [pincfg] + 0x12 0x411111f0 + + [verb] + 0x20 0x500 0x03 + 0x20 0x400 0xff + + [hint] + hp_detect = yes +------------------------------------------------------------------------ + +The file needs to have a line `[codec]`. The next line should contain +three numbers indicating the codec vendor-id (0x12345678 in the +example), the codec subsystem-id (0xabcd1234) and the address (2) of +the codec. The rest patch entries are applied to this specified codec +until another codec entry is given. + +The `[model]` line allows to change the model name of the each codec. +In the example above, it will be changed to model=auto. +Note that this overrides the module option. + +After the `[pincfg]` line, the contents are parsed as the initial +default pin-configurations just like `user_pin_configs` sysfs above. +The values can be shown in user_pin_configs sysfs file, too. + +Similarly, the lines after `[verb]` are parsed as `init_verbs` +sysfs entries, and the lines after `[hint]` are parsed as `hints` +sysfs entries, respectively. + + Power-Saving ~~~~~~~~~~~~ The power-saving is a kind of auto-suspend of the device. When the -- cgit v1.2.3-70-g09d2 From 1e7b8c87cb53d9a14f1a9ef35eed739f68851f5c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 17 Jun 2009 17:30:54 +0200 Subject: ALSA: hda - More description about patch module option Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 4 ++++ Documentation/sound/alsa/HD-Audio.txt | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 012858d2b11..414700b996a 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -749,6 +749,10 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. bdl_pos_adj - Specifies the DMA IRQ timing delay in samples. Passing -1 will make the driver to choose the appropriate value based on the controller chip. + patch - Specifies the early "patch" files to modify the HD-audio + setup before initializing the codecs. This option is + available only when CONFIG_SND_HDA_PATCH_LOADER=y is set. + See HD-Audio.txt for details. [Single (global) options] single_cmd - Use single immediate commands to communicate with diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 8bc9867c0a3..55aab116823 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -410,7 +410,7 @@ firmware file for modifying the HD-audio setup before initializing the codec. This can work basically like the reconfiguration via sysfs in the above, but it does it before the first codec configuration. -The patch file looks like below: +A patch file is a plain text file which looks like below: ------------------------------------------------------------------------ [codec] @@ -448,6 +448,20 @@ Similarly, the lines after `[verb]` are parsed as `init_verbs` sysfs entries, and the lines after `[hint]` are parsed as `hints` sysfs entries, respectively. +The hd-audio driver reads the file via request_firmware(). Thus, +a patch file has to be located on the appropriate firmware path, +typically, /lib/firmware. For example, when you pass the option +`patch=hda-init.fw`, the file /lib/firmware/hda-init-fw must be +present. + +The patch module option is specific to each card instance, and you +need to give one file name for each instance, separated by commas. +For example, if you have two cards, one for an on-board analog and one +for an HDMI video board, you may pass patch option like below: +------------------------------------------------------------------------ + options snd-hda-intel patch=on-board-patch,hdmi-patch +------------------------------------------------------------------------ + Power-Saving ~~~~~~~~~~~~ -- cgit v1.2.3-70-g09d2 From 4953550a6ca399b644ef057626617465d8be9a7b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 30 Jun 2009 15:28:30 +0200 Subject: ALSA: hda - Merge patch_alc882() and patch_alc883() Merge patch_alc882() and patch_alc883() to the former one since both codecs have fairly similar connections but just a slight difference. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 12 +- sound/pci/hda/patch_realtek.c | 1979 ++++++++++---------------- 2 files changed, 766 insertions(+), 1225 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 939a3dd5814..a1895d7f3cf 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -114,8 +114,8 @@ ALC662/663/272 samsung-nc10 Samsung NC10 mini notebook auto auto-config reading BIOS (default) -ALC882/885 -========== +ALC882/883/885/888/889 +====================== 3stack-dig 3-jack with SPDIF I/O 6stack-dig 6-jack digital with SPDIF I/O arima Arima W820Di1 @@ -127,12 +127,8 @@ ALC882/885 mbp3 Macbook Pro rev3 imac24 iMac 24'' with jack detection w2jc ASUS W2JC - auto auto-config reading BIOS (default) - -ALC883/888 -========== - 3stack-dig 3-jack with SPDIF I/O - 6stack-dig 6-jack digital with SPDIF I/O + 3stack-2ch-dig 3-jack with SPDIF I/O (ALC883) + alc883-6stack-dig 6-jack digital with SPDIF I/O (ALC883) 3stack-6ch 3-jack 6-channel 3stack-6ch-dig 3-jack 6-channel with SPDIF I/O 6stack-dig-demo 6-jack digital for Intel demo board diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3a8e58c483d..6a899e8fdd0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -208,12 +208,6 @@ enum { ALC885_MBP3, ALC885_MB5, ALC885_IMAC24, - ALC882_AUTO, - ALC882_MODEL_LAST, -}; - -/* ALC883 models */ -enum { ALC883_3ST_2ch_DIG, ALC883_3ST_6ch_DIG, ALC883_3ST_6ch, @@ -246,8 +240,8 @@ enum { ALC889A_MB31, ALC1200_ASUS_P5Q, ALC883_SONY_VAIO_TT, - ALC883_AUTO, - ALC883_MODEL_LAST, + ALC882_AUTO, + ALC882_MODEL_LAST, }; /* for GPIO Poll */ @@ -320,6 +314,8 @@ struct alc_spec { struct snd_array kctls; struct hda_input_mux private_imux[3]; hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; + hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS]; + hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS]; /* hooks */ void (*init_hook)(struct hda_codec *codec); @@ -6295,7 +6291,7 @@ static int patch_alc260(struct hda_codec *codec) /* - * ALC882 support + * ALC882/883/885/888/889 support * * ALC882 is almost identical with ALC880 but has cleaner and more flexible * configuration. Each pin widget can choose any input DACs and a mixer. @@ -6307,22 +6303,35 @@ static int patch_alc260(struct hda_codec *codec) */ #define ALC882_DIGOUT_NID 0x06 #define ALC882_DIGIN_NID 0x0a +#define ALC883_DIGOUT_NID ALC882_DIGOUT_NID +#define ALC883_DIGIN_NID ALC882_DIGIN_NID +#define ALC1200_DIGOUT_NID 0x10 + static struct hda_channel_mode alc882_ch_modes[1] = { { 8, NULL } }; +/* DACs */ static hda_nid_t alc882_dac_nids[4] = { /* front, rear, clfe, rear_surr */ 0x02, 0x03, 0x04, 0x05 }; +#define alc883_dac_nids alc882_dac_nids -/* identical with ALC880 */ +/* ADCs */ #define alc882_adc_nids alc880_adc_nids #define alc882_adc_nids_alt alc880_adc_nids_alt +#define alc883_adc_nids alc882_adc_nids_alt +static hda_nid_t alc883_adc_nids_alt[1] = { 0x08 }; +static hda_nid_t alc883_adc_nids_rev[2] = { 0x09, 0x08 }; +#define alc889_adc_nids alc880_adc_nids static hda_nid_t alc882_capsrc_nids[3] = { 0x24, 0x23, 0x22 }; static hda_nid_t alc882_capsrc_nids_alt[2] = { 0x23, 0x22 }; +#define alc883_capsrc_nids alc882_capsrc_nids_alt +static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; +#define alc889_capsrc_nids alc882_capsrc_nids /* input MUX */ /* FIXME: should be a matrix-type input source selection */ @@ -6337,6 +6346,8 @@ static struct hda_input_mux alc882_capture_source = { }, }; +#define alc883_capture_source alc882_capture_source + static struct hda_input_mux mb5_capture_source = { .num_items = 3, .items = { @@ -6346,6 +6357,77 @@ static struct hda_input_mux mb5_capture_source = { }, }; +static struct hda_input_mux alc883_3stack_6ch_intel = { + .num_items = 4, + .items = { + { "Mic", 0x1 }, + { "Front Mic", 0x0 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static struct hda_input_mux alc883_lenovo_101e_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x1 }, + { "Line", 0x2 }, + }, +}; + +static struct hda_input_mux alc883_lenovo_nb0763_capture_source = { + .num_items = 4, + .items = { + { "Mic", 0x0 }, + { "iMic", 0x1 }, + { "Line", 0x2 }, + { "CD", 0x4 }, + }, +}; + +static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "Int Mic", 0x1 }, + }, +}; + +static struct hda_input_mux alc883_lenovo_sky_capture_source = { + .num_items = 3, + .items = { + { "Mic", 0x0 }, + { "Front Mic", 0x1 }, + { "Line", 0x4 }, + }, +}; + +static struct hda_input_mux alc883_asus_eee1601_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + { "Line", 0x2 }, + }, +}; + +static struct hda_input_mux alc889A_mb31_capture_source = { + .num_items = 2, + .items = { + { "Mic", 0x0 }, + /* Front Mic (0x01) unused */ + { "Line", 0x2 }, + /* Line 2 (0x03) unused */ + /* CD (0x04) unsused? */ + }, +}; + +/* + * 2ch mode + */ +static struct hda_channel_mode alc883_3ST_2ch_modes[1] = { + { 2, NULL } +}; + /* * 2ch mode */ @@ -6357,6 +6439,18 @@ static struct hda_verb alc882_3ST_ch2_init[] = { { } /* end */ }; +/* + * 4ch mode + */ +static struct hda_verb alc882_3ST_ch4_init[] = { + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + /* * 6ch mode */ @@ -6370,11 +6464,14 @@ static struct hda_verb alc882_3ST_ch6_init[] = { { } /* end */ }; -static struct hda_channel_mode alc882_3ST_6ch_modes[2] = { +static struct hda_channel_mode alc882_3ST_6ch_modes[3] = { { 2, alc882_3ST_ch2_init }, + { 4, alc882_3ST_ch4_init }, { 6, alc882_3ST_ch6_init }, }; +#define alc883_3ST_6ch_modes alc882_3ST_6ch_modes + /* * 6ch mode */ @@ -6462,6 +6559,143 @@ static struct hda_channel_mode alc885_mb5_6ch_modes[2] = { { 6, alc885_mb5_ch6_init }, }; + +/* + * 2ch mode + */ +static struct hda_verb alc883_4ST_ch2_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static struct hda_verb alc883_4ST_ch4_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static struct hda_verb alc883_4ST_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static struct hda_verb alc883_4ST_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static struct hda_channel_mode alc883_4ST_8ch_modes[4] = { + { 2, alc883_4ST_ch2_init }, + { 4, alc883_4ST_ch4_init }, + { 6, alc883_4ST_ch6_init }, + { 8, alc883_4ST_ch8_init }, +}; + + +/* + * 2ch mode + */ +static struct hda_verb alc883_3ST_ch2_intel_init[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static struct hda_verb alc883_3ST_ch4_intel_init[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static struct hda_verb alc883_3ST_ch6_intel_init[] = { + { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { + { 2, alc883_3ST_ch2_intel_init }, + { 4, alc883_3ST_ch4_intel_init }, + { 6, alc883_3ST_ch6_intel_init }, +}; + +/* + * 6ch mode + */ +static struct hda_verb alc883_sixstack_ch6_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +/* + * 8ch mode + */ +static struct hda_verb alc883_sixstack_ch8_init[] = { + { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { } /* end */ +}; + +static struct hda_channel_mode alc883_sixstack_modes[2] = { + { 6, alc883_sixstack_ch6_init }, + { 8, alc883_sixstack_ch8_init }, +}; + + /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b */ @@ -6597,7 +6831,7 @@ static struct snd_kcontrol_new alc882_chmode_mixer[] = { { } /* end */ }; -static struct hda_verb alc882_init_verbs[] = { +static struct hda_verb alc882_base_init_verbs[] = { /* Front mixer: unmute input/output amp left and right (volume = 0) */ {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -6649,11 +6883,6 @@ static struct hda_verb alc882_init_verbs[] = { /* FIXME: use matrix-type input source selection */ /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, /* Input mixer2 */ {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, @@ -6664,9 +6893,6 @@ static struct hda_verb alc882_init_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* ADC1: mute amp left and right */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, /* ADC2: mute amp left and right */ {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -6677,6 +6903,21 @@ static struct hda_verb alc882_init_verbs[] = { { } }; +static struct hda_verb alc882_adc1_init_verbs[] = { + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + { } +}; + +/* HACK - expand to two elements */ +#define alc882_init_verbs alc882_base_init_verbs, alc882_adc1_init_verbs + static struct hda_verb alc882_eapd_verbs[] = { /* change to EAPD mode */ {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, @@ -6684,6 +6925,8 @@ static struct hda_verb alc882_eapd_verbs[] = { { } }; +#define alc883_init_verbs alc882_base_init_verbs + /* Mac Pro test */ static struct snd_kcontrol_new alc882_macpro_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), @@ -7034,882 +7277,62 @@ static void alc885_imac24_init_hook(struct hda_codec *codec) /* * generic initialization of ADC, input mixers and output mixers */ -static struct hda_verb alc882_auto_init_verbs[] = { +static struct hda_verb alc883_auto_init_verbs[] = { /* * Unmute ADC0-2 and set the default input to mic-in */ - {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - /* - * Set up output mixers (0x0c - 0x0f) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, - - { } -}; - -#ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc882_loopbacks alc880_loopbacks -#endif - -/* pcm configuration: identical with ALC880 */ -#define alc882_pcm_analog_playback alc880_pcm_analog_playback -#define alc882_pcm_analog_capture alc880_pcm_analog_capture -#define alc882_pcm_digital_playback alc880_pcm_digital_playback -#define alc882_pcm_digital_capture alc880_pcm_digital_capture - -/* - * configuration and preset - */ -static const char *alc882_models[ALC882_MODEL_LAST] = { - [ALC882_3ST_DIG] = "3stack-dig", - [ALC882_6ST_DIG] = "6stack-dig", - [ALC882_ARIMA] = "arima", - [ALC882_W2JC] = "w2jc", - [ALC882_TARGA] = "targa", - [ALC882_ASUS_A7J] = "asus-a7j", - [ALC882_ASUS_A7M] = "asus-a7m", - [ALC885_MACPRO] = "macpro", - [ALC885_MB5] = "mb5", - [ALC885_MBP3] = "mbp3", - [ALC885_IMAC24] = "imac24", - [ALC882_AUTO] = "auto", -}; - -static struct snd_pci_quirk alc882_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), - SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), - SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), - SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), - SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ - SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), - SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), - {} -}; - -static struct alc_config_preset alc882_presets[] = { - [ALC882_3ST_DIG] = { - .mixers = { alc882_base_mixer }, - .init_verbs = { alc882_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), - .channel_mode = alc882_ch_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - }, - [ALC882_6ST_DIG] = { - .mixers = { alc882_base_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), - .channel_mode = alc882_sixstack_modes, - .input_mux = &alc882_capture_source, - }, - [ALC882_ARIMA] = { - .mixers = { alc882_base_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs, alc882_eapd_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), - .channel_mode = alc882_sixstack_modes, - .input_mux = &alc882_capture_source, - }, - [ALC882_W2JC] = { - .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs, alc882_eapd_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - }, - [ALC885_MBP3] = { - .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, - .init_verbs = { alc885_mbp3_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mbp_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes), - .input_mux = &alc882_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc885_mbp3_init_hook, - }, - [ALC885_MB5] = { - .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, - .init_verbs = { alc885_mb5_init_verbs, - alc880_gpio1_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .channel_mode = alc885_mb5_6ch_modes, - .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes), - .input_mux = &mb5_capture_source, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - }, - [ALC885_MACPRO] = { - .mixers = { alc882_macpro_mixer }, - .init_verbs = { alc882_macpro_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), - .channel_mode = alc882_ch_modes, - .input_mux = &alc882_capture_source, - .init_hook = alc885_macpro_init_hook, - }, - [ALC885_IMAC24] = { - .mixers = { alc885_imac24_mixer }, - .init_verbs = { alc885_imac24_init_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .dig_in_nid = ALC882_DIGIN_NID, - .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), - .channel_mode = alc882_ch_modes, - .input_mux = &alc882_capture_source, - .unsol_event = alc_automute_amp_unsol_event, - .init_hook = alc885_imac24_init_hook, - }, - [ALC882_TARGA] = { - .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs, alc882_targa_verbs}, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), - .adc_nids = alc882_adc_nids, - .capsrc_nids = alc882_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes), - .channel_mode = alc882_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - .unsol_event = alc882_targa_unsol_event, - .init_hook = alc882_targa_init_hook, - }, - [ALC882_ASUS_A7J] = { - .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs}, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), - .adc_nids = alc882_adc_nids, - .capsrc_nids = alc882_capsrc_nids, - .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes), - .channel_mode = alc882_3ST_6ch_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - }, - [ALC882_ASUS_A7M] = { - .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer }, - .init_verbs = { alc882_init_verbs, alc882_eapd_verbs, - alc880_gpio1_init_verbs, - alc882_asus_a7m_verbs }, - .num_dacs = ARRAY_SIZE(alc882_dac_nids), - .dac_nids = alc882_dac_nids, - .dig_out_nid = ALC882_DIGOUT_NID, - .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), - .channel_mode = alc880_threestack_modes, - .need_dac_fix = 1, - .input_mux = &alc882_capture_source, - }, -}; - - -/* - * Pin config fixes - */ -enum { - PINFIX_ABIT_AW9D_MAX -}; - -static struct alc_pincfg alc882_abit_aw9d_pinfix[] = { - { 0x15, 0x01080104 }, /* side */ - { 0x16, 0x01011012 }, /* rear */ - { 0x17, 0x01016011 }, /* clfe */ - { } -}; - -static const struct alc_pincfg *alc882_pin_fixes[] = { - [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix, -}; - -static struct snd_pci_quirk alc882_pinfix_tbl[] = { - SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), - {} -}; - -/* - * BIOS auto configuration - */ -static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t nid, int pin_type, - int dac_idx) -{ - /* set as output */ - struct alc_spec *spec = codec->spec; - int idx; - - alc_set_pin_output(codec, nid, pin_type); - if (spec->multiout.dac_nids[dac_idx] == 0x25) - idx = 4; - else - idx = spec->multiout.dac_nids[dac_idx] - 2; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); - -} - -static void alc882_auto_init_multi_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i <= HDA_SIDE; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - int pin_type = get_pin_type(spec->autocfg.line_out_type); - if (nid) - alc882_auto_set_output_and_unmute(codec, nid, pin_type, - i); - } -} - -static void alc882_auto_init_hp_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t pin; - - pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - /* use dac 0 */ - alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); - pin = spec->autocfg.speaker_pins[0]; - if (pin) - alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); -} - -#define alc882_is_input_pin(nid) alc880_is_input_pin(nid) -#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID - -static void alc882_auto_init_analog_input(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < AUTO_PIN_LAST; i++) { - hda_nid_t nid = spec->autocfg.input_pins[i]; - if (!nid) - continue; - alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/); - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - } -} - -static void alc882_auto_init_input_src(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int c; - - for (c = 0; c < spec->num_adc_nids; c++) { - hda_nid_t conn_list[HDA_MAX_NUM_INPUTS]; - hda_nid_t nid = spec->capsrc_nids[c]; - unsigned int mux_idx; - const struct hda_input_mux *imux; - int conns, mute, idx, item; - - conns = snd_hda_get_connections(codec, nid, conn_list, - ARRAY_SIZE(conn_list)); - if (conns < 0) - continue; - mux_idx = c >= spec->num_mux_defs ? 0 : c; - imux = &spec->input_mux[mux_idx]; - for (idx = 0; idx < conns; idx++) { - /* if the current connection is the selected one, - * unmute it as default - otherwise mute it - */ - mute = AMP_IN_MUTE(idx); - for (item = 0; item < imux->num_items; item++) { - if (imux->items[item].index == idx) { - if (spec->cur_mux[c] == item) - mute = AMP_IN_UNMUTE(idx); - break; - } - } - /* check if we have a selector or mixer - * we could check for the widget type instead, but - * just check for Amp-In presence (in case of mixer - * without amp-in there is something wrong, this - * function shouldn't be used or capsrc nid is wrong) - */ - if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - mute); - else if (mute != AMP_IN_MUTE(idx)) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, - idx); - } - } -} - -/* add mic boosts if needed */ -static int alc_auto_add_mic_boost(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int err; - hda_nid_t nid; - - nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; - if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Mic Boost", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - } - nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; - if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Front Mic Boost", - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - } - return 0; -} - -/* almost identical with ALC880 parser... */ -static int alc882_parse_auto_config(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int err = alc880_parse_auto_config(codec); - - if (err < 0) - return err; - else if (!err) - return 0; /* no config found */ - - err = alc_auto_add_mic_boost(codec); - if (err < 0) - return err; - - /* hack - override the init verbs */ - spec->init_verbs[0] = alc882_auto_init_verbs; - - return 1; /* config found */ -} - -/* additional initialization for auto-configuration model */ -static void alc882_auto_init(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - alc882_auto_init_multi_out(codec); - alc882_auto_init_hp_out(codec); - alc882_auto_init_analog_input(codec); - alc882_auto_init_input_src(codec); - if (spec->unsol_event) - alc_inithook(codec); -} - -static int patch_alc883(struct hda_codec *codec); /* called in patch_alc882() */ - -static int patch_alc882(struct hda_codec *codec) -{ - struct alc_spec *spec; - int err, board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST, - alc882_models, - alc882_cfg_tbl); - - if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { - /* Pick up systems that don't supply PCI SSID */ - switch (codec->subsystem_id) { - case 0x106b0c00: /* Mac Pro */ - board_config = ALC885_MACPRO; - break; - case 0x106b1000: /* iMac 24 */ - case 0x106b2800: /* AppleTV */ - case 0x106b3e00: /* iMac 24 Aluminium */ - board_config = ALC885_IMAC24; - break; - case 0x106b00a0: /* MacBookPro3,1 - Another revision */ - case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */ - case 0x106b00a4: /* MacbookPro4,1 */ - case 0x106b2c00: /* Macbook Pro rev3 */ - /* Macbook 3.1 (0x106b3600) is handled by patch_alc883() */ - case 0x106b3800: /* MacbookPro4,1 - latter revision */ - board_config = ALC885_MBP3; - break; - case 0x106b3f00: /* Macbook 5,1 */ - case 0x106b4000: /* Macbook Pro 5,1 - FIXME: HP jack sense - * seems not working, so apparently - * no perfect solution yet - */ - board_config = ALC885_MB5; - break; - default: - /* ALC889A is handled better as ALC888-compatible */ - if (codec->revision_id == 0x100101 || - codec->revision_id == 0x100103) { - alc_free(codec); - return patch_alc883(codec); - } - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", - codec->chip_name); - board_config = ALC882_AUTO; - } - } - - alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes); - - if (board_config == ALC882_AUTO) { - /* automatic parse from the BIOS config */ - err = alc882_parse_auto_config(codec); - if (err < 0) { - alc_free(codec); - return err; - } else if (!err) { - printk(KERN_INFO - "hda_codec: Cannot set up configuration " - "from BIOS. Using base mode...\n"); - board_config = ALC882_3ST_DIG; - } - } - - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) { - alc_free(codec); - return err; - } - - if (board_config != ALC882_AUTO) - setup_preset(spec, &alc882_presets[board_config]); - - spec->stream_analog_playback = &alc882_pcm_analog_playback; - spec->stream_analog_capture = &alc882_pcm_analog_capture; - /* FIXME: setup DAC5 */ - /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/ - spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; - - spec->stream_digital_playback = &alc882_pcm_digital_playback; - spec->stream_digital_capture = &alc882_pcm_digital_capture; - - if (!spec->adc_nids && spec->input_mux) { - /* check whether NID 0x07 is valid */ - unsigned int wcap = get_wcaps(codec, 0x07); - /* get type */ - wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; - if (wcap != AC_WID_AUD_IN) { - spec->adc_nids = alc882_adc_nids_alt; - spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids_alt); - spec->capsrc_nids = alc882_capsrc_nids_alt; - } else { - spec->adc_nids = alc882_adc_nids; - spec->num_adc_nids = ARRAY_SIZE(alc882_adc_nids); - spec->capsrc_nids = alc882_capsrc_nids; - } - } - set_capture_mixer(spec); - set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - - spec->vmaster_nid = 0x0c; - - codec->patch_ops = alc_patch_ops; - if (board_config == ALC882_AUTO) - spec->init_hook = alc882_auto_init; -#ifdef CONFIG_SND_HDA_POWER_SAVE - if (!spec->loopback.amplist) - spec->loopback.amplist = alc882_loopbacks; -#endif - codec->proc_widget_hook = print_realtek_coef; - - return 0; -} - -/* - * ALC883 support - * - * ALC883 is almost identical with ALC880 but has cleaner and more flexible - * configuration. Each pin widget can choose any input DACs and a mixer. - * Each ADC is connected from a mixer of all inputs. This makes possible - * 6-channel independent captures. - * - * In addition, an independent DAC for the multi-playback (not used in this - * driver yet). - */ -#define ALC883_DIGOUT_NID 0x06 -#define ALC883_DIGIN_NID 0x0a - -#define ALC1200_DIGOUT_NID 0x10 - -static hda_nid_t alc883_dac_nids[4] = { - /* front, rear, clfe, rear_surr */ - 0x02, 0x03, 0x04, 0x05 -}; - -static hda_nid_t alc883_adc_nids[2] = { - /* ADC1-2 */ - 0x08, 0x09, -}; - -static hda_nid_t alc883_adc_nids_alt[1] = { - /* ADC1 */ - 0x08, -}; - -static hda_nid_t alc883_adc_nids_rev[2] = { - /* ADC2-1 */ - 0x09, 0x08 -}; - -#define alc889_adc_nids alc880_adc_nids - -static hda_nid_t alc883_capsrc_nids[2] = { 0x23, 0x22 }; - -static hda_nid_t alc883_capsrc_nids_rev[2] = { 0x22, 0x23 }; - -#define alc889_capsrc_nids alc882_capsrc_nids - -/* input MUX */ -/* FIXME: should be a matrix-type input source selection */ - -static struct hda_input_mux alc883_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static struct hda_input_mux alc883_3stack_6ch_intel = { - .num_items = 4, - .items = { - { "Mic", 0x1 }, - { "Front Mic", 0x0 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static struct hda_input_mux alc883_lenovo_101e_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "Line", 0x2 }, - }, -}; - -static struct hda_input_mux alc883_lenovo_nb0763_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "iMic", 0x1 }, - { "Line", 0x2 }, - { "CD", 0x4 }, - }, -}; - -static struct hda_input_mux alc883_fujitsu_pi2515_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Int Mic", 0x1 }, - }, -}; - -static struct hda_input_mux alc883_lenovo_sky_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Front Mic", 0x1 }, - { "Line", 0x4 }, - }, -}; - -static struct hda_input_mux alc883_asus_eee1601_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Line", 0x2 }, - }, -}; - -static struct hda_input_mux alc889A_mb31_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - /* Front Mic (0x01) unused */ - { "Line", 0x2 }, - /* Line 2 (0x03) unused */ - /* CD (0x04) unsused? */ - }, -}; - -/* - * 2ch mode - */ -static struct hda_channel_mode alc883_3ST_2ch_modes[1] = { - { 2, NULL } -}; - -/* - * 2ch mode - */ -static struct hda_verb alc883_3ST_ch2_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static struct hda_verb alc883_3ST_ch4_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static struct hda_verb alc883_3ST_ch6_init[] = { - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static struct hda_channel_mode alc883_3ST_6ch_modes[3] = { - { 2, alc883_3ST_ch2_init }, - { 4, alc883_3ST_ch4_init }, - { 6, alc883_3ST_ch6_init }, -}; - - -/* - * 2ch mode - */ -static struct hda_verb alc883_4ST_ch2_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static struct hda_verb alc883_4ST_ch4_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static struct hda_verb alc883_4ST_ch6_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 8ch mode - */ -static struct hda_verb alc883_4ST_ch8_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, - { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -static struct hda_channel_mode alc883_4ST_8ch_modes[4] = { - { 2, alc883_4ST_ch2_init }, - { 4, alc883_4ST_ch4_init }, - { 6, alc883_4ST_ch6_init }, - { 8, alc883_4ST_ch8_init }, -}; - - -/* - * 2ch mode - */ -static struct hda_verb alc883_3ST_ch2_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; - -/* - * 4ch mode - */ -static struct hda_verb alc883_3ST_ch4_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; - -/* - * 6ch mode - */ -static struct hda_verb alc883_3ST_ch6_intel_init[] = { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x19, AC_VERB_SET_CONNECT_SEL, 0x02 }, - { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, - { } /* end */ -}; + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, -static struct hda_channel_mode alc883_3ST_6ch_intel_modes[3] = { - { 2, alc883_3ST_ch2_intel_init }, - { 4, alc883_3ST_ch4_intel_init }, - { 6, alc883_3ST_ch6_intel_init }, -}; + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + * Note: PASD motherboards uses the Line In 2 as the input for + * front panel mic (mic 2) + */ + /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, -/* - * 6ch mode - */ -static struct hda_verb alc883_sixstack_ch6_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00 }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; + /* + * Set up output mixers (0x0c - 0x0f) + */ + /* set vol=0 to output mixers */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + /* set up input amps for analog loopback */ + /* Amp Indices: DAC = 0, mixer = 1 */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, -/* - * 8ch mode - */ -static struct hda_verb alc883_sixstack_ch8_init[] = { - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { } /* end */ -}; + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, -static struct hda_channel_mode alc883_sixstack_modes[2] = { - { 6, alc883_sixstack_ch6_init }, - { 8, alc883_sixstack_ch8_init }, + { } }; /* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */ @@ -7962,34 +7385,7 @@ static struct hda_verb alc883_medion_eapd_verbs[] = { { } }; -/* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 - * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b - */ - -static struct snd_kcontrol_new alc883_base_mixer[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), - { } /* end */ -}; +#define alc883_base_mixer alc882_base_mixer static struct snd_kcontrol_new alc883_mitac_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), @@ -8309,113 +7705,35 @@ static struct snd_kcontrol_new alc883_asus_eee1601_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), - { } /* end */ -}; - -static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { - HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol), - HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 1, - .info = alc_mux_enum_info, - .get = alc_mux_enum_get, - .put = alc_mux_enum_put, - }, - { } /* end */ -}; - -static struct snd_kcontrol_new alc883_chmode_mixer[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_ch_mode_info, - .get = alc_ch_mode_get, - .put = alc_ch_mode_put, - }, - { } /* end */ -}; - -static struct hda_verb alc883_init_verbs[] = { - /* ADC1: mute amp left and right */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* ADC2: mute amp left and right */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Front mixer: unmute input/output amp left and right (volume = 0) */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Rear mixer */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* CLFE mixer */ - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Side mixer */ - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - - /* mute analog input loopbacks */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; - /* Front Pin: output 0 (0x0c) */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Rear Pin: output 1 (0x0d) */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* CLFE Pin: output 2 (0x0e) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, - /* Side Pin: output 3 (0x0f) */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Mic (rear) pin: input vref at 80% */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Front Mic pin: input vref at 80% */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line In pin: input */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Line-2 In: Headphone output (output 0 - 0x0c) */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* CD pin widget for input */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, +static struct snd_kcontrol_new alc883_asus_eee1601_cap_mixer[] = { + HDA_BIND_VOL("Capture Volume", &alc883_bind_cap_vol), + HDA_BIND_SW("Capture Switch", &alc883_bind_cap_switch), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* .name = "Capture Source", */ + .name = "Input Source", + .count = 1, + .info = alc_mux_enum_info, + .get = alc_mux_enum_get, + .put = alc_mux_enum_put, + }, + { } /* end */ +}; - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer2 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Input mixer3 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - { } +static struct snd_kcontrol_new alc883_chmode_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = alc_ch_mode_info, + .get = alc_ch_mode_get, + .put = alc_ch_mode_put, + }, + { } /* end */ }; /* toggle speaker-output according to the hp-jack state */ @@ -8850,69 +8168,6 @@ static void alc883_vaiott_init_hook(struct hda_codec *codec) alc_automute_amp(codec); } -/* - * generic initialization of ADC, input mixers and output mixers - */ -static struct hda_verb alc883_auto_init_verbs[] = { - /* - * Unmute ADC0-2 and set the default input to mic-in - */ - {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - - /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback - * mixer widget - * Note: PASD motherboards uses the Line In 2 as the input for - * front panel mic (mic 2) - */ - /* Amp Indices: Mic1 = 0, Mic2 = 1, Line1 = 2, Line2 = 3, CD = 4 */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - - /* - * Set up output mixers (0x0c - 0x0f) - */ - /* set vol=0 to output mixers */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* set up input amps for analog loopback */ - /* Amp Indices: DAC = 0, mixer = 1 */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - - /* FIXME: use matrix-type input source selection */ - /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ - /* Input mixer1 */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */ - {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - /* Input mixer2 */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(2)}, - /* {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3)}, */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, - - { } -}; - static struct hda_verb alc888_asus_m90v_verbs[] = { {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, @@ -9023,25 +8278,44 @@ static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) alc889A_mb31_automute(codec); } + #ifdef CONFIG_SND_HDA_POWER_SAVE -#define alc883_loopbacks alc880_loopbacks +#define alc882_loopbacks alc880_loopbacks #endif /* pcm configuration: identical with ALC880 */ -#define alc883_pcm_analog_playback alc880_pcm_analog_playback -#define alc883_pcm_analog_capture alc880_pcm_analog_capture -#define alc883_pcm_analog_alt_capture alc880_pcm_analog_alt_capture -#define alc883_pcm_digital_playback alc880_pcm_digital_playback -#define alc883_pcm_digital_capture alc880_pcm_digital_capture +#define alc882_pcm_analog_playback alc880_pcm_analog_playback +#define alc882_pcm_analog_capture alc880_pcm_analog_capture +#define alc882_pcm_digital_playback alc880_pcm_digital_playback +#define alc882_pcm_digital_capture alc880_pcm_digital_capture + +static hda_nid_t alc883_slave_dig_outs[] = { + ALC1200_DIGOUT_NID, 0, +}; + +static hda_nid_t alc1200_slave_dig_outs[] = { + ALC883_DIGOUT_NID, 0, +}; /* * configuration and preset */ -static const char *alc883_models[ALC883_MODEL_LAST] = { - [ALC883_3ST_2ch_DIG] = "3stack-dig", +static const char *alc882_models[ALC882_MODEL_LAST] = { + [ALC882_3ST_DIG] = "3stack-dig", + [ALC882_6ST_DIG] = "6stack-dig", + [ALC882_ARIMA] = "arima", + [ALC882_W2JC] = "w2jc", + [ALC882_TARGA] = "targa", + [ALC882_ASUS_A7J] = "asus-a7j", + [ALC882_ASUS_A7M] = "asus-a7m", + [ALC885_MACPRO] = "macpro", + [ALC885_MB5] = "mb5", + [ALC885_MBP3] = "mbp3", + [ALC885_IMAC24] = "imac24", + [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig", [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig", [ALC883_3ST_6ch] = "3stack-6ch", - [ALC883_6ST_DIG] = "6stack-dig", + [ALC883_6ST_DIG] = "alc883-6stack-dig", [ALC883_TARGA_DIG] = "targa-dig", [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig", @@ -9068,11 +8342,12 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { [ALC1200_ASUS_P5Q] = "asus-p5q", [ALC889A_MB31] = "mb31", [ALC883_SONY_VAIO_TT] = "sony-vaio-tt", - [ALC883_AUTO] = "auto", + [ALC882_AUTO] = "auto", }; -static struct snd_pci_quirk alc883_cfg_tbl[] = { - SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC883_3ST_6ch_DIG), +static struct snd_pci_quirk alc882_cfg_tbl[] = { + SND_PCI_QUIRK(0x1019, 0x6668, "ECS", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_ACER_ASPIRE), SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_ACER_ASPIRE), @@ -9087,8 +8362,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { ALC888_ACER_ASPIRE_8930G), SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", ALC888_ACER_ASPIRE_8930G), - SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO), - SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO), + SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC882_AUTO), + SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC882_AUTO), SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", ALC888_ACER_ASPIRE_6530G), SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", @@ -9097,30 +8372,44 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { * model=auto should work fine now */ /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */ + SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), + SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a60, "HP Lucknow", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a61, "HP Nettle", ALC883_6ST_DIG), SND_PCI_QUIRK(0x103c, 0x2a66, "HP Acacia", ALC888_3ST_HP), SND_PCI_QUIRK(0x103c, 0x2a72, "HP Educ.ar", ALC888_3ST_HP), + + SND_PCI_QUIRK(0x1043, 0x060d, "Asus A7J", ALC882_ASUS_A7J), + SND_PCI_QUIRK(0x1043, 0x1243, "Asus A7J", ALC882_ASUS_A7J), + SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_ASUS_A7M), SND_PCI_QUIRK(0x1043, 0x1873, "Asus M90V", ALC888_ASUS_M90V), + SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_W2JC), + SND_PCI_QUIRK(0x1043, 0x817f, "Asus P5LD2", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x1043, 0x81d8, "Asus P5WD", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x8249, "Asus M2A-VM HDMI", ALC883_3ST_6ch_DIG), SND_PCI_QUIRK(0x1043, 0x8284, "Asus Z37E", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1043, 0x82fe, "Asus P5Q-EM HDMI", ALC1200_ASUS_P5Q), SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_ASUS_EEE1601), + + SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT), SND_PCI_QUIRK(0x105b, 0x0ce8, "Foxconn P35AX-S", ALC883_6ST_DIG), - SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x105b, 0x6668, "Foxconn", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1071, 0x8227, "Mitac 82801H", ALC883_MITAC), SND_PCI_QUIRK(0x1071, 0x8253, "Mitac 8252d", ALC883_MITAC), SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC883_LAPTOP_EAPD), SND_PCI_QUIRK(0x10f1, 0x2350, "TYAN-S2350", ALC888_6ST_DELL), SND_PCI_QUIRK(0x108e, 0x534d, NULL, ALC883_3ST_6ch), - SND_PCI_QUIRK(0x1458, 0xa002, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P35 DS3R", ALC882_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x0349, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3b7f, "MSI", ALC883_TARGA_2ch_DIG), @@ -9142,11 +8431,13 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720), SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD), SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), + /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */ SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_MEDION), SND_PCI_QUIRK_MASK(0x1734, 0xfff0, 0x1100, "FSC AMILO Xi/Pi25xx", ALC883_FUJITSU_PI2515), @@ -9161,24 +8452,175 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { SND_PCI_QUIRK(0x17c0, 0x4085, "MEDION MD96630", ALC888_LENOVO_MS7195_DIG), SND_PCI_QUIRK(0x17f2, 0x5000, "Albatron KI690-AM2", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1991, 0x5625, "Haier W66", ALC883_HAIER_W66), + SND_PCI_QUIRK(0x8086, 0x0001, "DG33BUC", ALC883_3ST_6ch_INTEL), SND_PCI_QUIRK(0x8086, 0x0002, "DG33FBC", ALC883_3ST_6ch_INTEL), SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC), SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL), SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), - SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT), - {} -}; -static hda_nid_t alc883_slave_dig_outs[] = { - ALC1200_DIGOUT_NID, 0, + {} }; -static hda_nid_t alc1200_slave_dig_outs[] = { - ALC883_DIGOUT_NID, 0, +/* codec SSID table for Intel Mac */ +static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { + SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_MACPRO), + SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24), + SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), + SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), + SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), + SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), + SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), + /* FIXME: HP jack sense seems not working for MBP 5,1, so apparently + * no perfect solution yet + */ + SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), + {} /* terminator */ }; -static struct alc_config_preset alc883_presets[] = { +static struct alc_config_preset alc882_presets[] = { + [ALC882_3ST_DIG] = { + .mixers = { alc882_base_mixer }, + .init_verbs = { alc882_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), + .channel_mode = alc882_ch_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + }, + [ALC882_6ST_DIG] = { + .mixers = { alc882_base_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), + .channel_mode = alc882_sixstack_modes, + .input_mux = &alc882_capture_source, + }, + [ALC882_ARIMA] = { + .mixers = { alc882_base_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_init_verbs, alc882_eapd_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc882_sixstack_modes), + .channel_mode = alc882_sixstack_modes, + .input_mux = &alc882_capture_source, + }, + [ALC882_W2JC] = { + .mixers = { alc882_w2jc_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_init_verbs, alc882_eapd_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + }, + [ALC885_MBP3] = { + .mixers = { alc885_mbp3_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_mbp3_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mbp_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mbp_6ch_modes), + .input_mux = &alc882_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc885_mbp3_init_hook, + }, + [ALC885_MB5] = { + .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_mb5_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mb5_6ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes), + .input_mux = &mb5_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + }, + [ALC885_MACPRO] = { + .mixers = { alc882_macpro_mixer }, + .init_verbs = { alc882_macpro_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), + .channel_mode = alc882_ch_modes, + .input_mux = &alc882_capture_source, + .init_hook = alc885_macpro_init_hook, + }, + [ALC885_IMAC24] = { + .mixers = { alc885_imac24_mixer }, + .init_verbs = { alc885_imac24_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), + .channel_mode = alc882_ch_modes, + .input_mux = &alc882_capture_source, + .unsol_event = alc_automute_amp_unsol_event, + .init_hook = alc885_imac24_init_hook, + }, + [ALC882_TARGA] = { + .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_init_verbs, alc882_targa_verbs}, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), + .adc_nids = alc882_adc_nids, + .capsrc_nids = alc882_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes), + .channel_mode = alc882_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + .unsol_event = alc882_targa_unsol_event, + .init_hook = alc882_targa_init_hook, + }, + [ALC882_ASUS_A7J] = { + .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_init_verbs, alc882_asus_a7j_verbs}, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .num_adc_nids = ARRAY_SIZE(alc882_adc_nids), + .adc_nids = alc882_adc_nids, + .capsrc_nids = alc882_capsrc_nids, + .num_channel_mode = ARRAY_SIZE(alc882_3ST_6ch_modes), + .channel_mode = alc882_3ST_6ch_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + }, + [ALC882_ASUS_A7M] = { + .mixers = { alc882_asus_a7m_mixer, alc882_chmode_mixer }, + .init_verbs = { alc882_init_verbs, alc882_eapd_verbs, + alc880_gpio1_init_verbs, + alc882_asus_a7m_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .dig_out_nid = ALC882_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc880_threestack_modes), + .channel_mode = alc880_threestack_modes, + .need_dac_fix = 1, + .input_mux = &alc882_capture_source, + }, [ALC883_3ST_2ch_DIG] = { .mixers = { alc883_3ST_2ch_mixer }, .init_verbs = { alc883_init_verbs }, @@ -9612,10 +9054,33 @@ static struct alc_config_preset alc883_presets[] = { }; +/* + * Pin config fixes + */ +enum { + PINFIX_ABIT_AW9D_MAX +}; + +static struct alc_pincfg alc882_abit_aw9d_pinfix[] = { + { 0x15, 0x01080104 }, /* side */ + { 0x16, 0x01011012 }, /* rear */ + { 0x17, 0x01016011 }, /* clfe */ + { } +}; + +static const struct alc_pincfg *alc882_pin_fixes[] = { + [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix, +}; + +static struct snd_pci_quirk alc882_pinfix_tbl[] = { + SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX), + {} +}; + /* * BIOS auto configuration */ -static void alc883_auto_set_output_and_unmute(struct hda_codec *codec, +static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, hda_nid_t nid, int pin_type, int dac_idx) { @@ -9632,7 +9097,7 @@ static void alc883_auto_set_output_and_unmute(struct hda_codec *codec, } -static void alc883_auto_init_multi_out(struct hda_codec *codec) +static void alc882_auto_init_multi_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int i; @@ -9641,12 +9106,12 @@ static void alc883_auto_init_multi_out(struct hda_codec *codec) hda_nid_t nid = spec->autocfg.line_out_pins[i]; int pin_type = get_pin_type(spec->autocfg.line_out_type); if (nid) - alc883_auto_set_output_and_unmute(codec, nid, pin_type, + alc882_auto_set_output_and_unmute(codec, nid, pin_type, i); } } -static void alc883_auto_init_hp_out(struct hda_codec *codec) +static void alc882_auto_init_hp_out(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; hda_nid_t pin; @@ -9654,42 +9119,114 @@ static void alc883_auto_init_hp_out(struct hda_codec *codec) pin = spec->autocfg.hp_pins[0]; if (pin) /* connect to front */ /* use dac 0 */ - alc883_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); + alc882_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); pin = spec->autocfg.speaker_pins[0]; if (pin) - alc883_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); + alc882_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); } -#define alc883_is_input_pin(nid) alc880_is_input_pin(nid) -#define ALC883_PIN_CD_NID ALC880_PIN_CD_NID +#define alc882_is_input_pin(nid) alc880_is_input_pin(nid) +#define ALC882_PIN_CD_NID ALC880_PIN_CD_NID -static void alc883_auto_init_analog_input(struct hda_codec *codec) +static void alc882_auto_init_analog_input(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; int i; for (i = 0; i < AUTO_PIN_LAST; i++) { hda_nid_t nid = spec->autocfg.input_pins[i]; - if (alc883_is_input_pin(nid)) { - alc_set_input_pin(codec, nid, i); - if (nid != ALC883_PIN_CD_NID && - (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) + if (!nid) + continue; + alc_set_input_pin(codec, nid, AUTO_PIN_FRONT_MIC /*i*/); + if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_MUTE); + } +} + +static void alc882_auto_init_input_src(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int c; + + for (c = 0; c < spec->num_adc_nids; c++) { + hda_nid_t conn_list[HDA_MAX_NUM_INPUTS]; + hda_nid_t nid = spec->capsrc_nids[c]; + unsigned int mux_idx; + const struct hda_input_mux *imux; + int conns, mute, idx, item; + + conns = snd_hda_get_connections(codec, nid, conn_list, + ARRAY_SIZE(conn_list)); + if (conns < 0) + continue; + mux_idx = c >= spec->num_mux_defs ? 0 : c; + imux = &spec->input_mux[mux_idx]; + for (idx = 0; idx < conns; idx++) { + /* if the current connection is the selected one, + * unmute it as default - otherwise mute it + */ + mute = AMP_IN_MUTE(idx); + for (item = 0; item < imux->num_items; item++) { + if (imux->items[item].index == idx) { + if (spec->cur_mux[c] == item) + mute = AMP_IN_UNMUTE(idx); + break; + } + } + /* check if we have a selector or mixer + * we could check for the widget type instead, but + * just check for Amp-In presence (in case of mixer + * without amp-in there is something wrong, this + * function shouldn't be used or capsrc nid is wrong) + */ + if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); + mute); + else if (mute != AMP_IN_MUTE(idx)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, + idx); } } } -#define alc883_auto_init_input_src alc882_auto_init_input_src +/* add mic boosts if needed */ +static int alc_auto_add_mic_boost(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + int err; + hda_nid_t nid; + + nid = spec->autocfg.input_pins[AUTO_PIN_MIC]; + if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) { + err = add_control(spec, ALC_CTL_WIDGET_VOL, + "Mic Boost", + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } + nid = spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]; + if (nid && (get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) { + err = add_control(spec, ALC_CTL_WIDGET_VOL, + "Front Mic Boost", + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + } + return 0; +} /* almost identical with ALC880 parser... */ -static int alc883_parse_auto_config(struct hda_codec *codec) +static int alc882_parse_auto_config(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - int err = alc880_parse_auto_config(codec); - struct auto_pin_cfg *cfg = &spec->autocfg; + struct auto_pin_cfg *autocfg = &spec->autocfg; + unsigned int wcap; int i; + int err = alc880_parse_auto_config(codec); if (err < 0) return err; @@ -9702,43 +9239,45 @@ static int alc883_parse_auto_config(struct hda_codec *codec) /* hack - override the init verbs */ spec->init_verbs[0] = alc883_auto_init_verbs; + /* if ADC 0x07 is available, initialize it, too */ + wcap = get_wcaps(codec, 0x07); + wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + if (wcap == AC_WID_AUD_IN) + add_verb(spec, alc882_adc1_init_verbs); - /* setup input_mux for ALC889 */ - if (codec->vendor_id == 0x10ec0889) { - /* digital-mic input pin is excluded in alc880_auto_create..() - * because it's under 0x18 - */ - if (cfg->input_pins[AUTO_PIN_MIC] == 0x12 || - cfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) { - struct hda_input_mux *imux = &spec->private_imux[0]; - for (i = 1; i < 3; i++) - memcpy(&spec->private_imux[i], - &spec->private_imux[0], - sizeof(spec->private_imux[0])); - imux->items[imux->num_items].label = "Int DMic"; - imux->items[imux->num_items].index = 0x0b; - imux->num_items++; - spec->num_mux_defs = 3; - spec->input_mux = spec->private_imux; - } + /* digital-mic input pin is excluded in alc880_auto_create..() + * because it's under 0x18 + */ + if (autocfg->input_pins[AUTO_PIN_MIC] == 0x12 || + autocfg->input_pins[AUTO_PIN_FRONT_MIC] == 0x12) { + struct hda_input_mux *imux = &spec->private_imux[0]; + for (i = 1; i < 3; i++) + memcpy(&spec->private_imux[i], + &spec->private_imux[0], + sizeof(spec->private_imux[0])); + imux->items[imux->num_items].label = "Int DMic"; + imux->items[imux->num_items].index = 0x0b; + imux->num_items++; + spec->num_mux_defs = 3; + spec->input_mux = spec->private_imux; } return 1; /* config found */ } /* additional initialization for auto-configuration model */ -static void alc883_auto_init(struct hda_codec *codec) +static void alc882_auto_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - alc883_auto_init_multi_out(codec); - alc883_auto_init_hp_out(codec); - alc883_auto_init_analog_input(codec); - alc883_auto_init_input_src(codec); + alc882_auto_init_multi_out(codec); + alc882_auto_init_hp_out(codec); + alc882_auto_init_analog_input(codec); + alc882_auto_init_input_src(codec); if (spec->unsol_event) alc_inithook(codec); } -static int patch_alc883(struct hda_codec *codec) +static int patch_alc882(struct hda_codec *codec) { struct alc_spec *spec; int err, board_config; @@ -9749,28 +9288,36 @@ static int patch_alc883(struct hda_codec *codec) codec->spec = spec; - alc_fix_pll_init(codec, 0x20, 0x0a, 10); + switch (codec->vendor_id) { + case 0x10ec0882: + case 0x10ec0885: + break; + default: + /* ALC883 and variants */ + alc_fix_pll_init(codec, 0x20, 0x0a, 10); + break; + } - board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, - alc883_models, - alc883_cfg_tbl); - if (board_config < 0 || board_config >= ALC883_MODEL_LAST) { - /* Pick up systems that don't supply PCI SSID */ - switch (codec->subsystem_id) { - case 0x106b3600: /* Macbook 3.1 */ - board_config = ALC889A_MB31; - break; - default: - printk(KERN_INFO - "hda_codec: Unknown model for %s, trying " - "auto-probe from BIOS...\n", codec->chip_name); - board_config = ALC883_AUTO; - } + board_config = snd_hda_check_board_config(codec, ALC882_MODEL_LAST, + alc882_models, + alc882_cfg_tbl); + + if (board_config < 0 || board_config >= ALC882_MODEL_LAST) + board_config = snd_hda_check_board_codec_sid_config(codec, + ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl); + + if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { + printk(KERN_INFO "hda_codec: Unknown model for %s, " + "trying auto-probe from BIOS...\n", + codec->chip_name); + board_config = ALC882_AUTO; } - if (board_config == ALC883_AUTO) { + alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes); + + if (board_config == ALC882_AUTO) { /* automatic parse from the BIOS config */ - err = alc883_parse_auto_config(codec); + err = alc882_parse_auto_config(codec); if (err < 0) { alc_free(codec); return err; @@ -9778,7 +9325,7 @@ static int patch_alc883(struct hda_codec *codec) printk(KERN_INFO "hda_codec: Cannot set up configuration " "from BIOS. Using base mode...\n"); - board_config = ALC883_3ST_2ch_DIG; + board_config = ALC882_3ST_DIG; } } @@ -9788,63 +9335,61 @@ static int patch_alc883(struct hda_codec *codec) return err; } - if (board_config != ALC883_AUTO) - setup_preset(spec, &alc883_presets[board_config]); + if (board_config != ALC882_AUTO) + setup_preset(spec, &alc882_presets[board_config]); - switch (codec->vendor_id) { - case 0x10ec0888: - if (!spec->num_adc_nids) { - spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); - spec->adc_nids = alc883_adc_nids; - } - if (!spec->capsrc_nids) - spec->capsrc_nids = alc883_capsrc_nids; + spec->stream_analog_playback = &alc882_pcm_analog_playback; + spec->stream_analog_capture = &alc882_pcm_analog_capture; + /* FIXME: setup DAC5 */ + /*spec->stream_analog_alt_playback = &alc880_pcm_analog_alt_playback;*/ + spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; + + spec->stream_digital_playback = &alc882_pcm_digital_playback; + spec->stream_digital_capture = &alc882_pcm_digital_capture; + + if (codec->vendor_id == 0x10ec0888) spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */ - break; - case 0x10ec0889: - if (!spec->num_adc_nids) { - spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids); - spec->adc_nids = alc889_adc_nids; - } - if (!spec->capsrc_nids) - spec->capsrc_nids = alc889_capsrc_nids; - break; - default: - if (!spec->num_adc_nids) { - spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); - spec->adc_nids = alc883_adc_nids; + + if (!spec->adc_nids && spec->input_mux) { + int i; + spec->num_adc_nids = 0; + for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) { + hda_nid_t cap; + hda_nid_t nid = alc882_adc_nids[i]; + unsigned int wcap = get_wcaps(codec, nid); + /* get type */ + wcap = (wcap & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; + if (wcap != AC_WID_AUD_IN) + continue; + spec->private_adc_nids[spec->num_adc_nids] = nid; + err = snd_hda_get_connections(codec, nid, &cap, 1); + if (err < 0) + continue; + spec->private_capsrc_nids[spec->num_adc_nids] = cap; + spec->num_adc_nids++; } - if (!spec->capsrc_nids) - spec->capsrc_nids = alc883_capsrc_nids; - break; + spec->adc_nids = spec->private_adc_nids; + spec->capsrc_nids = spec->private_capsrc_nids; } - spec->stream_analog_playback = &alc883_pcm_analog_playback; - spec->stream_analog_capture = &alc883_pcm_analog_capture; - spec->stream_analog_alt_capture = &alc883_pcm_analog_alt_capture; - - spec->stream_digital_playback = &alc883_pcm_digital_playback; - spec->stream_digital_capture = &alc883_pcm_digital_capture; - - if (!spec->cap_mixer) - set_capture_mixer(spec); + set_capture_mixer(spec); set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); spec->vmaster_nid = 0x0c; codec->patch_ops = alc_patch_ops; - if (board_config == ALC883_AUTO) - spec->init_hook = alc883_auto_init; - + if (board_config == ALC882_AUTO) + spec->init_hook = alc882_auto_init; #ifdef CONFIG_SND_HDA_POWER_SAVE if (!spec->loopback.amplist) - spec->loopback.amplist = alc883_loopbacks; + spec->loopback.amplist = alc882_loopbacks; #endif codec->proc_widget_hook = print_realtek_coef; return 0; } + /* * ALC262 support */ @@ -17546,23 +17091,23 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 }, { .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd }, { .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2", - .patch = patch_alc883 }, + .patch = patch_alc882 }, { .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1", .patch = patch_alc662 }, { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, - { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc883 }, + { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, { .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A", - .patch = patch_alc882 }, /* should be patch_alc883() in future */ + .patch = patch_alc882 }, { .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A", - .patch = patch_alc882 }, /* should be patch_alc883() in future */ + .patch = patch_alc882 }, { .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 }, - { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc883 }, + { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 }, { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200", - .patch = patch_alc883 }, - { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc883 }, - { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc883 }, + .patch = patch_alc882 }, + { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 }, + { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 }, {} /* terminator */ }; -- cgit v1.2.3-70-g09d2 From 020e5f85cb087a40572c8b8b2dd06292a14fa212 Mon Sep 17 00:00:00 2001 From: Li Zefan Date: Wed, 1 Jul 2009 10:47:05 +0800 Subject: tracing/events: Add trace_event boot option We already have ftrace= boot option, and this adds a similar boot option for trace events, so allow trace events to be enabled at boot, for boot debugging purpose. Signed-off-by: Li Zefan Cc: Steven Rostedt Cc: Frederic Weisbecker LKML-Reference: <4A4ACE29.3010407@cn.fujitsu.com> Signed-off-by: Ingo Molnar --- Documentation/kernel-parameters.txt | 5 +++++ Documentation/trace/events.txt | 9 +++++++++ kernel/trace/trace.c | 4 ++-- kernel/trace/trace.h | 3 +++ kernel/trace/trace_events.c | 37 +++++++++++++++++++++++++++++++++---- 5 files changed, 52 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index d3f41db3ed4..2582e7aea29 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2478,6 +2478,11 @@ and is between 256 and 4096 characters. It is defined in the file trace_buf_size=nn[KMG] [FTRACE] will set tracing buffer size. + trace_event=[event-list] + [FTRACE] Set and start specified trace events in order + to facilitate early boot debugging. + See also Documentation/trace/events.txt + trix= [HW,OSS] MediaTrix AudioTrix Pro Format: ,,,,,,,, diff --git a/Documentation/trace/events.txt b/Documentation/trace/events.txt index f157d7594ea..2bcc8d4dea2 100644 --- a/Documentation/trace/events.txt +++ b/Documentation/trace/events.txt @@ -83,6 +83,15 @@ When reading one of these enable files, there are four results: X - there is a mixture of events enabled and disabled ? - this file does not affect any event +2.3 Boot option +--------------- + +In order to facilitate early boot debugging, use boot option: + + trace_event=[event-list] + +The format of this boot option is the same as described in section 2.1. + 3. Defining an event-enabled tracepoint ======================================= diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 3aa0a0dfdfa..bdb3afc8b30 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -49,7 +49,7 @@ unsigned long __read_mostly tracing_thresh; * On boot up, the ring buffer is set to the minimum size, so that * we do not waste memory on systems that are not using tracing. */ -static int ring_buffer_expanded; +int ring_buffer_expanded; /* * We need to change this state when a selftest is running. @@ -63,7 +63,7 @@ static bool __read_mostly tracing_selftest_running; /* * If a tracer is running, we do not want to run SELFTEST. */ -static bool __read_mostly tracing_selftest_disabled; +bool __read_mostly tracing_selftest_disabled; /* For tracers that don't implement custom flags */ static struct tracer_opt dummy_tracer_opt[] = { diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 3548ae5cc78..52eb0d8dcd7 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -517,6 +517,9 @@ extern unsigned long ftrace_update_tot_cnt; extern int DYN_FTRACE_TEST_NAME(void); #endif +extern int ring_buffer_expanded; +extern bool tracing_selftest_disabled; + #ifdef CONFIG_FTRACE_STARTUP_TEST extern int trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr); diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 53c8fd376a8..fecac1314cb 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -17,6 +17,8 @@ #include #include +#include + #include "trace_output.h" #define TRACE_SYSTEM "TRACE_SYSTEM" @@ -1133,6 +1135,18 @@ struct notifier_block trace_module_nb = { extern struct ftrace_event_call __start_ftrace_events[]; extern struct ftrace_event_call __stop_ftrace_events[]; +static char bootup_event_buf[COMMAND_LINE_SIZE] __initdata; + +static __init int setup_trace_event(char *str) +{ + strlcpy(bootup_event_buf, str, COMMAND_LINE_SIZE); + ring_buffer_expanded = 1; + tracing_selftest_disabled = 1; + + return 1; +} +__setup("trace_event=", setup_trace_event); + static __init int event_trace_init(void) { struct ftrace_event_call *call; @@ -1140,6 +1154,8 @@ static __init int event_trace_init(void) struct dentry *entry; struct dentry *d_events; int ret; + char *buf = bootup_event_buf; + char *token; d_tracer = tracing_init_dentry(); if (!d_tracer) @@ -1185,6 +1201,19 @@ static __init int event_trace_init(void) &ftrace_event_format_fops); } + while (true) { + token = strsep(&buf, ","); + + if (!token) + break; + if (!*token) + continue; + + ret = ftrace_set_clr_event(token, 1); + if (ret) + pr_warning("Failed to enable trace event: %s\n", token); + } + ret = register_module_notifier(&trace_module_nb); if (ret) pr_warning("Failed to register trace events module notifier\n"); @@ -1392,10 +1421,10 @@ static __init void event_trace_self_test_with_function(void) static __init int event_trace_self_tests_init(void) { - - event_trace_self_tests(); - - event_trace_self_test_with_function(); + if (!tracing_selftest_disabled) { + event_trace_self_tests(); + event_trace_self_test_with_function(); + } return 0; } -- cgit v1.2.3-70-g09d2 From 240ebbf81f149b11a31e060ebe5ee51a3c775360 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 25 Jun 2009 09:08:18 -0700 Subject: rcu: Add synchronize_sched_expedited() rcutorture doc + updates This patch updates the rcutorture documentation to include updated output format. It also brings the RCU documentation up to date. Signed-off-by: Paul E. McKenney Cc: akpm@linux-foundation.org Cc: torvalds@linux-foundation.org Cc: davem@davemloft.net Cc: dada1@cosmosbay.com Cc: zbr@ioremap.net Cc: jeff.chua.linux@gmail.com Cc: paulus@samba.org Cc: laijs@cn.fujitsu.com Cc: jengelh@medozas.de Cc: r000n@r000n.net Cc: benh@kernel.crashing.org Cc: mathieu.desnoyers@polymtl.ca LKML-Reference: <12459460983193-git-send-email-> Signed-off-by: Ingo Molnar --- Documentation/RCU/RTFP.txt | 77 ++++++++++++++++++++++++++++++++++++++++ Documentation/RCU/UP.txt | 34 +++++++++++++----- Documentation/RCU/checklist.txt | 20 ++++++++--- Documentation/RCU/rcubarrier.txt | 7 ++++ Documentation/RCU/torture.txt | 23 ++++++++++-- Documentation/RCU/whatisRCU.txt | 14 ++++++-- 6 files changed, 156 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/RCU/RTFP.txt b/Documentation/RCU/RTFP.txt index 9f711d2df91..d2b85237c76 100644 --- a/Documentation/RCU/RTFP.txt +++ b/Documentation/RCU/RTFP.txt @@ -743,3 +743,80 @@ Revised: RCU, realtime RCU, sleepable RCU, performance. " } + +@article{PaulEMcKenney2008RCUOSR +,author="Paul E. McKenney and Jonathan Walpole" +,title="Introducing technology into the {Linux} kernel: a case study" +,Year="2008" +,journal="SIGOPS Oper. Syst. Rev." +,volume="42" +,number="5" +,pages="4--17" +,issn="0163-5980" +,doi={http://doi.acm.org/10.1145/1400097.1400099} +,publisher="ACM" +,address="New York, NY, USA" +,annotation={ + Linux changed RCU to a far greater degree than RCU has changed Linux. +} +} + +@unpublished{PaulEMcKenney2008HierarchicalRCU +,Author="Paul E. McKenney" +,Title="Hierarchical {RCU}" +,month="November" +,day="3" +,year="2008" +,note="Available: +\url{http://lwn.net/Articles/305782/} +[Viewed November 6, 2008]" +,annotation=" + RCU with combining-tree-based grace-period detection, + permitting it to handle thousands of CPUs. +" +} + +@conference{PaulEMcKenney2009MaliciousURCU +,Author="Paul E. McKenney" +,Title="Using a Malicious User-Level {RCU} to Torture {RCU}-Based Algorithms" +,Booktitle="linux.conf.au 2009" +,month="January" +,year="2009" +,address="Hobart, Australia" +,note="Available: +\url{http://www.rdrop.com/users/paulmck/RCU/urcutorture.2009.01.22a.pdf} +[Viewed February 2, 2009]" +,annotation=" + Realtime RCU and torture-testing RCU uses. +" +} + +@unpublished{MathieuDesnoyers2009URCU +,Author="Mathieu Desnoyers" +,Title="[{RFC} git tree] Userspace {RCU} (urcu) for {Linux}" +,month="February" +,day="5" +,year="2009" +,note="Available: +\url{http://lkml.org/lkml/2009/2/5/572} +\url{git://lttng.org/userspace-rcu.git} +[Viewed February 20, 2009]" +,annotation=" + Mathieu Desnoyers's user-space RCU implementation. + git://lttng.org/userspace-rcu.git +" +} + +@unpublished{PaulEMcKenney2009BloatWatchRCU +,Author="Paul E. McKenney" +,Title="{RCU}: The {Bloatwatch} Edition" +,month="March" +,day="17" +,year="2009" +,note="Available: +\url{http://lwn.net/Articles/323929/} +[Viewed March 20, 2009]" +,annotation=" + Uniprocessor assumptions allow simplified RCU implementation. +" +} diff --git a/Documentation/RCU/UP.txt b/Documentation/RCU/UP.txt index aab4a9ec393..90ec5341ee9 100644 --- a/Documentation/RCU/UP.txt +++ b/Documentation/RCU/UP.txt @@ -2,14 +2,13 @@ RCU on Uniprocessor Systems A common misconception is that, on UP systems, the call_rcu() primitive -may immediately invoke its function, and that the synchronize_rcu() -primitive may return immediately. The basis of this misconception +may immediately invoke its function. The basis of this misconception is that since there is only one CPU, it should not be necessary to wait for anything else to get done, since there are no other CPUs for anything else to be happening on. Although this approach will -sort- -of- work a surprising amount of the time, it is a very bad idea in general. -This document presents three examples that demonstrate exactly how bad an -idea this is. +This document presents three examples that demonstrate exactly how bad +an idea this is. Example 1: softirq Suicide @@ -82,11 +81,18 @@ Quick Quiz #2: What locking restriction must RCU callbacks respect? Summary -Permitting call_rcu() to immediately invoke its arguments or permitting -synchronize_rcu() to immediately return breaks RCU, even on a UP system. -So do not do it! Even on a UP system, the RCU infrastructure -must- -respect grace periods, and -must- invoke callbacks from a known environment -in which no locks are held. +Permitting call_rcu() to immediately invoke its arguments breaks RCU, +even on a UP system. So do not do it! Even on a UP system, the RCU +infrastructure -must- respect grace periods, and -must- invoke callbacks +from a known environment in which no locks are held. + +It -is- safe for synchronize_sched() and synchronize_rcu_bh() to return +immediately on an UP system. It is also safe for synchronize_rcu() +to return immediately on UP systems, except when running preemptable +RCU. + +Quick Quiz #3: Why can't synchronize_rcu() return immediately on + UP systems running preemptable RCU? Answer to Quick Quiz #1: @@ -117,3 +123,13 @@ Answer to Quick Quiz #2: callbacks acquire locks directly. However, a great many RCU callbacks do acquire locks -indirectly-, for example, via the kfree() primitive. + +Answer to Quick Quiz #3: + Why can't synchronize_rcu() return immediately on UP systems + running preemptable RCU? + + Because some other task might have been preempted in the middle + of an RCU read-side critical section. If synchronize_rcu() + simply immediately returned, it would prematurely signal the + end of the grace period, which would come as a nasty shock to + that other thread when it started running again. diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt index accfe2f5247..51525a30e8b 100644 --- a/Documentation/RCU/checklist.txt +++ b/Documentation/RCU/checklist.txt @@ -11,7 +11,10 @@ over a rather long period of time, but improvements are always welcome! structure is updated more than about 10% of the time, then you should strongly consider some other approach, unless detailed performance measurements show that RCU is nonetheless - the right tool for the job. + the right tool for the job. Yes, you might think of RCU + as simply cutting overhead off of the readers and imposing it + on the writers. That is exactly why normal uses of RCU will + do much more reading than updating. Another exception is where performance is not an issue, and RCU provides a simpler implementation. An example of this situation @@ -240,10 +243,11 @@ over a rather long period of time, but improvements are always welcome! instead need to use synchronize_irq() or synchronize_sched(). 12. Any lock acquired by an RCU callback must be acquired elsewhere - with irq disabled, e.g., via spin_lock_irqsave(). Failing to - disable irq on a given acquisition of that lock will result in - deadlock as soon as the RCU callback happens to interrupt that - acquisition's critical section. + with softirq disabled, e.g., via spin_lock_irqsave(), + spin_lock_bh(), etc. Failing to disable irq on a given + acquisition of that lock will result in deadlock as soon as the + RCU callback happens to interrupt that acquisition's critical + section. 13. RCU callbacks can be and are executed in parallel. In many cases, the callback code simply wrappers around kfree(), so that this @@ -310,3 +314,9 @@ over a rather long period of time, but improvements are always welcome! Because these primitives only wait for pre-existing readers, it is the caller's responsibility to guarantee safety to any subsequent readers. + +16. The various RCU read-side primitives do -not- contain memory + barriers. The CPU (and in some cases, the compiler) is free + to reorder code into and out of RCU read-side critical sections. + It is the responsibility of the RCU update-side primitives to + deal with this. diff --git a/Documentation/RCU/rcubarrier.txt b/Documentation/RCU/rcubarrier.txt index 909602d409b..e439a0edee2 100644 --- a/Documentation/RCU/rcubarrier.txt +++ b/Documentation/RCU/rcubarrier.txt @@ -170,6 +170,13 @@ module invokes call_rcu() from timers, you will need to first cancel all the timers, and only then invoke rcu_barrier() to wait for any remaining RCU callbacks to complete. +Of course, if you module uses call_rcu_bh(), you will need to invoke +rcu_barrier_bh() before unloading. Similarly, if your module uses +call_rcu_sched(), you will need to invoke rcu_barrier_sched() before +unloading. If your module uses call_rcu(), call_rcu_bh(), -and- +call_rcu_sched(), then you will need to invoke each of rcu_barrier(), +rcu_barrier_bh(), and rcu_barrier_sched(). + Implementing rcu_barrier() diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index a342b6e1cc1..9dba3bb90e6 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt @@ -76,8 +76,10 @@ torture_type The type of RCU to test: "rcu" for the rcu_read_lock() API, "rcu_sync" for rcu_read_lock() with synchronous reclamation, "rcu_bh" for the rcu_read_lock_bh() API, "rcu_bh_sync" for rcu_read_lock_bh() with synchronous reclamation, "srcu" for - the "srcu_read_lock()" API, and "sched" for the use of - preempt_disable() together with synchronize_sched(). + the "srcu_read_lock()" API, "sched" for the use of + preempt_disable() together with synchronize_sched(), + and "sched_expedited" for the use of preempt_disable() + with synchronize_sched_expedited(). verbose Enable debug printk()s. Default is disabled. @@ -162,6 +164,23 @@ of the "old" and "current" counters for the corresponding CPU. The "idx" value maps the "old" and "current" values to the underlying array, and is useful for debugging. +Similarly, sched_expedited RCU provides the following: + + sched_expedited-torture: rtc: d0000000016c1880 ver: 1090796 tfle: 0 rta: 1090796 rtaf: 0 rtf: 1090787 rtmbe: 0 nt: 27713319 + sched_expedited-torture: Reader Pipe: 12660320201 95875 0 0 0 0 0 0 0 0 0 + sched_expedited-torture: Reader Batch: 12660424885 0 0 0 0 0 0 0 0 0 0 + sched_expedited-torture: Free-Block Circulation: 1090795 1090795 1090794 1090793 1090792 1090791 1090790 1090789 1090788 1090787 0 + state: -1 / 0:0 3:0 4:0 + +As before, the first four lines are similar to those for RCU. +The last line shows the task-migration state. The first number is +-1 if synchronize_sched_expedited() is idle, -2 if in the process of +posting wakeups to the migration kthreads, and N when waiting on CPU N. +Each of the colon-separated fields following the "/" is a CPU:state pair. +Valid states are "0" for idle, "1" for waiting for quiescent state, +"2" for passed through quiescent state, and "3" when a race with a +CPU-hotplug event forces use of the synchronize_sched() primitive. + USAGE diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index 96170824a71..97ded2432c5 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -785,6 +785,7 @@ RCU pointer/list traversal: rcu_dereference list_for_each_entry_rcu hlist_for_each_entry_rcu + hlist_nulls_for_each_entry_rcu list_for_each_continue_rcu (to be deprecated in favor of new list_for_each_entry_continue_rcu) @@ -807,19 +808,23 @@ RCU: Critical sections Grace period Barrier rcu_read_lock synchronize_net rcu_barrier rcu_read_unlock synchronize_rcu + synchronize_rcu_expedited call_rcu bh: Critical sections Grace period Barrier rcu_read_lock_bh call_rcu_bh rcu_barrier_bh - rcu_read_unlock_bh + rcu_read_unlock_bh synchronize_rcu_bh + synchronize_rcu_bh_expedited sched: Critical sections Grace period Barrier - [preempt_disable] synchronize_sched rcu_barrier_sched - [and friends] call_rcu_sched + rcu_read_lock_sched synchronize_sched rcu_barrier_sched + rcu_read_unlock_sched call_rcu_sched + [preempt_disable] synchronize_sched_expedited + [and friends] SRCU: Critical sections Grace period Barrier @@ -827,6 +832,9 @@ SRCU: Critical sections Grace period Barrier srcu_read_lock synchronize_srcu N/A srcu_read_unlock +SRCU: Initialization/cleanup + init_srcu_struct + cleanup_srcu_struct See the comment headers in the source code (or the docbook generated from them) for more information. -- cgit v1.2.3-70-g09d2 From 96ccd4a43a4d80c80be636cd025a69959cf47424 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 5 Jul 2009 12:47:52 +0200 Subject: genirq: Remove obsolete defines and typedefs The defines and typedefs (hw_interrupt_type, no_irq_type, irq_desc_t) have been kept around for migration reasons. The last users are gone, remove them. Signed-off-by: Thomas Gleixner --- Documentation/feature-removal-schedule.txt | 9 --------- include/linux/irq.h | 7 ------- 2 files changed, 16 deletions(-) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index f8cd450be9a..2af78126b05 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -394,15 +394,6 @@ Who: Thomas Gleixner ----------------------------- -What: obsolete generic irq defines and typedefs -When: 2.6.30 -Why: The defines and typedefs (hw_interrupt_type, no_irq_type, irq_desc_t) - have been kept around for migration reasons. After more than two years - it's time to remove them finally -Who: Thomas Gleixner - ---------------------------- - What: fakephp and associated sysfs files in /sys/bus/pci/slots/ When: 2011 Why: In 2.6.27, the semantics of /sys/bus/pci/slots was redefined to diff --git a/include/linux/irq.h b/include/linux/irq.h index cb2e77a3f7f..6956df9961a 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -219,13 +219,6 @@ static inline struct irq_desc *move_irq_desc(struct irq_desc *desc, int node) extern struct irq_desc *irq_to_desc_alloc_node(unsigned int irq, int node); -/* - * Migration helpers for obsolete names, they will go away: - */ -#define hw_interrupt_type irq_chip -#define no_irq_type no_irq_chip -typedef struct irq_desc irq_desc_t; - /* * Pick up the arch-dependent methods: */ -- cgit v1.2.3-70-g09d2 From a6bae20559bb0371e89ebc46689e9cf4e7816813 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 6 Jul 2009 15:15:22 +0200 Subject: ALSA: hda - Add quirk for MacBook Pro 5,5 with CS4206 Add the default pin configs for MBP55. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 4 ++ sound/pci/hda/patch_cirrus.c | 57 ++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index a1895d7f3cf..4d120a66fc7 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -381,3 +381,7 @@ STAC9872 ======== vaio VAIO laptop without SPDIF auto BIOS setup (default) + +Cirrus Logic CS4206/4207 +======================== + mbp55 MacBook Pro 5,5 diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 404c120991b..b1fd183d760 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -30,6 +30,7 @@ */ struct cs_spec { + int board_config; struct auto_pin_cfg autocfg; struct hda_multi_out multiout; struct snd_kcontrol *vmaster_sw; @@ -58,6 +59,13 @@ struct cs_spec { unsigned int mic_detect:1; }; +/* available models */ +enum { + CS420X_MBP55, + CS420X_AUTO, + CS420X_MODELS +}; + /* Vendor-specific processing widget */ #define CS420X_VENDOR_NID 0x11 #define CS_DIG_OUT1_PIN_NID 0x10 @@ -1038,6 +1046,49 @@ static int cs_parse_auto_config(struct hda_codec *codec) return 0; } +static const char *cs420x_models[CS420X_MODELS] = { + [CS420X_MBP55] = "mbp55", + [CS420X_AUTO] = "auto", +}; + + +static struct snd_pci_quirk cs420x_cfg_tbl[] = { + SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), + {} /* terminator */ +}; + +struct cs_pincfg { + hda_nid_t nid; + u32 val; +}; + +static struct cs_pincfg mbp55_pincfgs[] = { + { 0x09, 0x012b4030 }, + { 0x0a, 0x90100121 }, + { 0x0b, 0x90100120 }, + { 0x0c, 0x400000f0 }, + { 0x0d, 0x90a00110 }, + { 0x0e, 0x400000f0 }, + { 0x0f, 0x400000f0 }, + { 0x10, 0x014be040 }, + { 0x12, 0x400000f0 }, + { 0x15, 0x400000f0 }, + {} /* terminator */ +}; + +static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { + [CS420X_MBP55] = mbp55_pincfgs, +}; + +static void fix_pincfg(struct hda_codec *codec, int model) +{ + const struct cs_pincfg *cfg = cs_pincfgs[model]; + if (!cfg) + return; + for (; cfg->nid; cfg++) + snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); +} + static int patch_cs420x(struct hda_codec *codec) { @@ -1049,6 +1100,12 @@ static int patch_cs420x(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; + spec->board_config = + snd_hda_check_board_config(codec, CS420X_MODELS, + cs420x_models, cs420x_cfg_tbl); + if (spec->board_config >= 0) + fix_pincfg(codec, spec->board_config); + err = cs_parse_auto_config(codec); if (err < 0) goto error; -- cgit v1.2.3-70-g09d2 From 8b2c70d1e43074cc06afe99b0de12b686d9c9d02 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Wed, 10 Jun 2009 15:45:41 -0400 Subject: ring-buffer: add design document This adds the design document for the ring buffer and also explains how it is designed to have lockless writes. Signed-off-by: Steven Rostedt --- Documentation/trace/ring-buffer-design.txt | 955 +++++++++++++++++++++++++++++ 1 file changed, 955 insertions(+) create mode 100644 Documentation/trace/ring-buffer-design.txt (limited to 'Documentation') diff --git a/Documentation/trace/ring-buffer-design.txt b/Documentation/trace/ring-buffer-design.txt new file mode 100644 index 00000000000..5b1d23d604c --- /dev/null +++ b/Documentation/trace/ring-buffer-design.txt @@ -0,0 +1,955 @@ + Lockless Ring Buffer Design + =========================== + +Copyright 2009 Red Hat Inc. + Author: Steven Rostedt + License: The GNU Free Documentation License, Version 1.2 + (dual licensed under the GPL v2) +Reviewers: Mathieu Desnoyers, Huang Ying, Hidetoshi Seto, + and Frederic Weisbecker. + + +Written for: 2.6.31 + +Terminology used in this Document +--------------------------------- + +tail - where new writes happen in the ring buffer. + +head - where new reads happen in the ring buffer. + +producer - the task that writes into the ring buffer (same as writer) + +writer - same as producer + +consumer - the task that reads from the buffer (same as reader) + +reader - same as consumer. + +reader_page - A page outside the ring buffer used solely (for the most part) + by the reader. + +head_page - a pointer to the page that the reader will use next + +tail_page - a pointer to the page that will be written to next + +commit_page - a pointer to the page with the last finished non nested write. + +cmpxchg - hardware assisted atomic transaction that performs the following: + + A = B iff previous A == C + + R = cmpxchg(A, C, B) is saying that we replace A with B if and only if + current A is equal to C, and we put the old (current) A into R + + R gets the previous A regardless if A is updated with B or not. + + To see if the update was successful a compare of R == C may be used. + +The Generic Ring Buffer +----------------------- + +The ring buffer can be used in either an overwrite mode or in +producer/consumer mode. + +Producer/consumer mode is where the producer were to fill up the +buffer before the consumer could free up anything, the producer +will stop writing to the buffer. This will lose most recent events. + +Overwrite mode is where the produce were to fill up the buffer +before the consumer could free up anything, the producer will +overwrite the older data. This will lose the oldest events. + +No two writers can write at the same time (on the same per cpu buffer), +but a writer may interrupt another writer, but it must finish writing +before the previous writer may continue. This is very important to the +algorithm. The writers act like a "stack". The way interrupts works +enforces this behavior. + + + writer1 start + writer2 start + writer3 start + writer3 finishes + writer2 finishes + writer1 finishes + +This is very much like a writer being preempted by an interrupt and +the interrupt doing a write as well. + +Readers can happen at any time. But no two readers may run at the +same time, nor can a reader preempt/interrupt another reader. A reader +can not preempt/interrupt a writer, but it may read/consume from the +buffer at the same time as a writer is writing, but the reader must be +on another processor to do so. A reader may read on its own processor +and can be preempted by a writer. + +A writer can preempt a reader, but a reader can not preempt a writer. +But a reader can read the buffer at the same time (on another processor) +as a writer. + +The ring buffer is made up of a list of pages held together by a link list. + +At initialization a reader page is allocated for the reader that is not +part of the ring buffer. + +The head_page, tail_page and commit_page are all initialized to point +to the same page. + +The reader page is initialized to have its next pointer pointing to +the head page, and its previous pointer pointing to a page before +the head page. + +The reader has its own page to use. At start up time, this page is +allocated but is not attached to the list. When the reader wants +to read from the buffer, if its page is empty (like it is on start up) +it will swap its page with the head_page. The old reader page will +become part of the ring buffer and the head_page will be removed. +The page after the inserted page (old reader_page) will become the +new head page. + +Once the new page is given to the reader, the reader could do what +it wants with it, as long as a writer has left that page. + +A sample of how the reader page is swapped: Note this does not +show the head page in the buffer, it is for demonstrating a swap +only. + + +------+ + |reader| RING BUFFER + |page | + +------+ + +---+ +---+ +---+ + | |-->| |-->| | + | |<--| |<--| | + +---+ +---+ +---+ + ^ | ^ | + | +-------------+ | + +-----------------+ + + + +------+ + |reader| RING BUFFER + |page |-------------------+ + +------+ v + | +---+ +---+ +---+ + | | |-->| |-->| | + | | |<--| |<--| |<-+ + | +---+ +---+ +---+ | + | ^ | ^ | | + | | +-------------+ | | + | +-----------------+ | + +------------------------------------+ + + +------+ + |reader| RING BUFFER + |page |-------------------+ + +------+ <---------------+ v + | ^ +---+ +---+ +---+ + | | | |-->| |-->| | + | | | | | |<--| |<-+ + | | +---+ +---+ +---+ | + | | | ^ | | + | | +-------------+ | | + | +-----------------------------+ | + +------------------------------------+ + + +------+ + |buffer| RING BUFFER + |page |-------------------+ + +------+ <---------------+ v + | ^ +---+ +---+ +---+ + | | | | | |-->| | + | | New | | | |<--| |<-+ + | | Reader +---+ +---+ +---+ | + | | page ----^ | | + | | | | + | +-----------------------------+ | + +------------------------------------+ + + + +It is possible that the page swapped is the commit page and the tail page, +if what is in the ring buffer is less than what is held in a buffer page. + + + reader page commit page tail page + | | | + v | | + +---+ | | + | |<----------+ | + | |<------------------------+ + | |------+ + +---+ | + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |--->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +This case is still valid for this algorithm. +When the writer leaves the page, it simply goes into the ring buffer +since the reader page still points to the next location in the ring +buffer. + + +The main pointers: + + reader page - The page used solely by the reader and is not part + of the ring buffer (may be swapped in) + + head page - the next page in the ring buffer that will be swapped + with the reader page. + + tail page - the page where the next write will take place. + + commit page - the page that last finished a write. + +The commit page only is updated by the outer most writer in the +writer stack. A writer that preempts another writer will not move the +commit page. + +When data is written into the ring buffer, a position is reserved +in the ring buffer and passed back to the writer. When the writer +is finished writing data into that position, it commits the write. + +Another write (or a read) may take place at anytime during this +transaction. If another write happens it must finish before continuing +with the previous write. + + + Write reserve: + + Buffer page + +---------+ + |written | + +---------+ <--- given back to writer (current commit) + |reserved | + +---------+ <--- tail pointer + | empty | + +---------+ + + Write commit: + + Buffer page + +---------+ + |written | + +---------+ + |written | + +---------+ <--- next positon for write (current commit) + | empty | + +---------+ + + + If a write happens after the first reserve: + + Buffer page + +---------+ + |written | + +---------+ <-- current commit + |reserved | + +---------+ <--- given back to second writer + |reserved | + +---------+ <--- tail pointer + + After second writer commits: + + + Buffer page + +---------+ + |written | + +---------+ <--(last full commit) + |reserved | + +---------+ + |pending | + |commit | + +---------+ <--- tail pointer + + When the first writer commits: + + Buffer page + +---------+ + |written | + +---------+ + |written | + +---------+ + |written | + +---------+ <--(last full commit and tail pointer) + + +The commit pointer points to the last write location that was +committed without preempting another write. When a write that +preempted another write is committed, it only becomes a pending commit +and will not be a full commit till all writes have been committed. + +The commit page points to the page that has the last full commit. +The tail page points to the page with the last write (before +committing). + +The tail page is always equal to or after the commit page. It may +be several pages ahead. If the tail page catches up to the commit +page then no more writes may take place (regardless of the mode +of the ring buffer: overwrite and produce/consumer). + +The order of pages are: + + head page + commit page + tail page + +Possible scenario: + tail page + head page commit page | + | | | + v v v + +---+ +---+ +---+ +---+ +<---| |--->| |--->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +There is a special case that the head page is after either the commit page +and possibly the tail page. That is when the commit (and tail) page has been +swapped with the reader page. This is because the head page is always +part of the ring buffer, but the reader page is not. When ever there +has been less than a full page that has been committed inside the ring buffer, +and a reader swaps out a page, it will be swapping out the commit page. + + + reader page commit page tail page + | | | + v | | + +---+ | | + | |<----------+ | + | |<------------------------+ + | |------+ + +---+ | + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |--->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + ^ + | + head page + + +In this case, the head page will not move when the tail and commit +move back into the ring buffer. + +The reader can not swap a page into the ring buffer if the commit page +is still on that page. If the read meets the last commit (real commit +not pending or reserved), then there is nothing more to read. +The buffer is considered empty until another full commit finishes. + +When the tail meets the head page, if the buffer is in overwrite mode, +the head page will be pushed ahead one. If the buffer is in producer/consumer +mode, the write will fail. + +Overwrite mode: + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |--->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + ^ + | + head page + + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |--->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + ^ + | + head page + + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |--->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + ^ + | + head page + +Note, the reader page will still point to the previous head page. +But when a swap takes place, it will use the most recent head page. + + +Making the Ring Buffer Lockless: +-------------------------------- + +The main idea behind the lockless algorithm is to combine the moving +of the head_page pointer with the swapping of pages with the reader. +State flags are placed inside the pointer to the page. To do this, +each page must be aligned in memory by 4 bytes. This will allow the 2 +least significant bits of the address to be used as flags. Since +they will always be zero for the address. To get the address, +simply mask out the flags. + + MASK = ~3 + + address & MASK + +Two flags will be kept by these two bits: + + HEADER - the page being pointed to is a head page + + UPDATE - the page being pointed to is being updated by a writer + and was or is about to be a head page. + + + reader page + | + v + +---+ + | |------+ + +---+ | + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-H->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + + +The above pointer "-H->" would have the HEADER flag set. That is +the next page is the next page to be swapped out by the reader. +This pointer means the next page is the head page. + +When the tail page meets the head pointer, it will use cmpxchg to +change the pointer to the UPDATE state: + + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-H->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +"-U->" represents a pointer in the UPDATE state. + +Any access to the reader will need to take some sort of lock to serialize +the readers. But the writers will never take a lock to write to the +ring buffer. This means we only need to worry about a single reader, +and writes only preempt in "stack" formation. + +When the reader tries to swap the page with the ring buffer, it +will also use cmpxchg. If the flag bit in the pointer to the +head page does not have the HEADER flag set, the compare will fail +and the reader will need to look for the new head page and try again. +Note, the flag UPDATE and HEADER are never set at the same time. + +The reader swaps the reader page as follows: + + +------+ + |reader| RING BUFFER + |page | + +------+ + +---+ +---+ +---+ + | |--->| |--->| | + | |<---| |<---| | + +---+ +---+ +---+ + ^ | ^ | + | +---------------+ | + +-----H-------------+ + +The reader sets the reader page next pointer as HEADER to the page after +the head page. + + + +------+ + |reader| RING BUFFER + |page |-------H-----------+ + +------+ v + | +---+ +---+ +---+ + | | |--->| |--->| | + | | |<---| |<---| |<-+ + | +---+ +---+ +---+ | + | ^ | ^ | | + | | +---------------+ | | + | +-----H-------------+ | + +--------------------------------------+ + +It does a cmpxchg with the pointer to the previous head page to make it +point to the reader page. Note that the new pointer does not have the HEADER +flag set. This action atomically moves the head page forward. + + +------+ + |reader| RING BUFFER + |page |-------H-----------+ + +------+ v + | ^ +---+ +---+ +---+ + | | | |-->| |-->| | + | | | |<--| |<--| |<-+ + | | +---+ +---+ +---+ | + | | | ^ | | + | | +-------------+ | | + | +-----------------------------+ | + +------------------------------------+ + +After the new head page is set, the previous pointer of the head page is +updated to the reader page. + + +------+ + |reader| RING BUFFER + |page |-------H-----------+ + +------+ <---------------+ v + | ^ +---+ +---+ +---+ + | | | |-->| |-->| | + | | | | | |<--| |<-+ + | | +---+ +---+ +---+ | + | | | ^ | | + | | +-------------+ | | + | +-----------------------------+ | + +------------------------------------+ + + +------+ + |buffer| RING BUFFER + |page |-------H-----------+ <--- New head page + +------+ <---------------+ v + | ^ +---+ +---+ +---+ + | | | | | |-->| | + | | New | | | |<--| |<-+ + | | Reader +---+ +---+ +---+ | + | | page ----^ | | + | | | | + | +-----------------------------+ | + +------------------------------------+ + +Another important point. The page that the reader page points back to +by its previous pointer (the one that now points to the new head page) +never points back to the reader page. That is because the reader page is +not part of the ring buffer. Traversing the ring buffer via the next pointers +will always stay in the ring buffer. Traversing the ring buffer via the +prev pointers may not. + +Note, the way to determine a reader page is simply by examining the previous +pointer of the page. If the next pointer of the previous page does not +point back to the original page, then the original page is a reader page: + + + +--------+ + | reader | next +----+ + | page |-------->| |<====== (buffer page) + +--------+ +----+ + | | ^ + | v | next + prev | +----+ + +------------->| | + +----+ + +The way the head page moves forward: + +When the tail page meets the head page and the buffer is in overwrite mode +and more writes take place, the head page must be moved forward before the +writer may move the tail page. The way this is done is that the writer +performs a cmpxchg to convert the pointer to the head page from the HEADER +flag to have the UPDATE flag set. Once this is done, the reader will +not be able to swap the head page from the buffer, nor will it be able to +move the head page, until the writer is finished with the move. + +This eliminates any races that the reader can have on the writer. The reader +must spin, and this is why the reader can not preempt the writer. + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-H->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +The following page will be made into the new head page. + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |-H->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +After the new head page has been set, we can set the old head page +pointer back to NORMAL. + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |--->| |-H->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +After the head page has been moved, the tail page may now move forward. + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |--->| |-H->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + + +The above are the trivial updates. Now for the more complex scenarios. + + +As stated before, if enough writes preempt the first write, the +tail page may make it all the way around the buffer and meet the commit +page. At this time, we must start dropping writes (usually with some kind +of warning to the user). But what happens if the commit was still on the +reader page? The commit page is not part of the ring buffer. The tail page +must account for this. + + + reader page commit page + | | + v | + +---+ | + | |<----------+ + | | + | |------+ + +---+ | + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-H->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + ^ + | + tail page + +If the tail page were to simply push the head page forward, the commit when +leaving the reader page would not be pointing to the correct page. + +The solution to this is to test if the commit page is on the reader page +before pushing the head page. If it is, then it can be assumed that the +tail page wrapped the buffer, and we must drop new writes. + +This is not a race condition, because the commit page can only be moved +by the outter most writer (the writer that was preempted). +This means that the commit will not move while a writer is moving the +tail page. The reader can not swap the reader page if it is also being +used as the commit page. The reader can simply check that the commit +is off the reader page. Once the commit page leaves the reader page +it will never go back on it unless a reader does another swap with the +buffer page that is also the commit page. + + +Nested writes +------------- + +In the pushing forward of the tail page we must first push forward +the head page if the head page is the next page. If the head page +is not the next page, the tail page is simply updated with a cmpxchg. + +Only writers move the tail page. This must be done atomically to protect +against nested writers. + + temp_page = tail_page + next_page = temp_page->next + cmpxchg(tail_page, temp_page, next_page) + +The above will update the tail page if it is still pointing to the expected +page. If this fails, a nested write pushed it forward, the the current write +does not need to push it. + + + temp page + | + v + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |--->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +Nested write comes in and moves the tail page forward: + + tail page (moved by nested writer) + temp page | + | | + v v + +---+ +---+ +---+ +---+ +<---| |--->| |--->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +The above would fail the cmpxchg, but since the tail page has already +been moved forward, the writer will just try again to reserve storage +on the new tail page. + +But the moving of the head page is a bit more complex. + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-H->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +The write converts the head page pointer to UPDATE. + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +But if a nested writer preempts here. It will see that the next +page is a head page, but it is also nested. It will detect that +it is nested and will save that information. The detection is the +fact that it sees the UPDATE flag instead of a HEADER or NORMAL +pointer. + +The nested writer will set the new head page pointer. + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |-H->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +But it will not reset the update back to normal. Only the writer +that converted a pointer from HEAD to UPDATE will convert it back +to NORMAL. + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |-H->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +After the nested writer finishes, the outer most writer will convert +the UPDATE pointer to NORMAL. + + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |--->| |-H->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + + +It can be even more complex if several nested writes came in and moved +the tail page ahead several pages: + + +(first writer) + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-H->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +The write converts the head page pointer to UPDATE. + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |--->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +Next writer comes in, and sees the update and sets up the new +head page. + +(second writer) + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |-H->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +The nested writer moves the tail page forward. But does not set the old +update page to NORMAL because it is not the outer most writer. + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |-H->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +Another writer preempts and sees the page after the tail page is a head page. +It changes it from HEAD to UPDATE. + +(third writer) + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |-U->| |---> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +The writer will move the head page forward: + + +(third writer) + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |-U->| |-H-> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +But now that the third writer did change the HEAD flag to UPDATE it +will convert it to normal: + + +(third writer) + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |--->| |-H-> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + + +Then it will move the tail page, and return back to the second writer. + + +(second writer) + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |--->| |-H-> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + + +The second writer will fail to move the tail page because it was already +moved, so it will try again and add its data to the new tail page. +It will return to the first writer. + + +(first writer) + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |--->| |-H-> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +The first writer can not know atomically test if the tail page moved +while it updates the HEAD page. It will then update the head page to +what it thinks is the new head page. + + +(first writer) + + tail page + | + v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |-H->| |-H-> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +Since the cmpxchg returns the old value of the pointer the first writer +will see it succeeded in updating the pointer from NORMAL to HEAD. +But as we can see, this is not good enough. It must also check to see +if the tail page is either where it use to be or on the next page: + + +(first writer) + + A B tail page + | | | + v v v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |-H->| |-H-> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +If tail page != A and tail page does not equal B, then it must reset the +pointer back to NORMAL. The fact that it only needs to worry about +nested writers, it only needs to check this after setting the HEAD page. + + +(first writer) + + A B tail page + | | | + v v v + +---+ +---+ +---+ +---+ +<---| |--->| |-U->| |--->| |-H-> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + +Now the writer can update the head page. This is also why the head page must +remain in UPDATE and only reset by the outer most writer. This prevents +the reader from seeing the incorrect head page. + + +(first writer) + + A B tail page + | | | + v v v + +---+ +---+ +---+ +---+ +<---| |--->| |--->| |--->| |-H-> +--->| |<---| |<---| |<---| |<--- + +---+ +---+ +---+ +---+ + -- cgit v1.2.3-70-g09d2 From bff38771e1065c7fc3de87e47ba366151eea573c Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Wed, 8 Jul 2009 11:10:56 -0700 Subject: netpoll: Introduce netpoll_carrier_timeout kernel option Some PHYs require longer timeouts for carrier detection, and auto-negotiation process may take indefinite amount of time. It may be inconvenient to force longer timeouts for sane PHYs, so let's introduce a kernel command line option. Since we're using module_param(), the option also can be changed in runtime. Signed-off-by: Anton Vorontsov Signed-off-by: David S. Miller --- Documentation/kernel-parameters.txt | 5 +++++ net/core/netpoll.c | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index d77fbd8b79a..9347f4ad434 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1531,6 +1531,11 @@ and is between 256 and 4096 characters. It is defined in the file symbolic names: lapic and ioapic Example: nmi_watchdog=2 or nmi_watchdog=panic,lapic + netpoll.carrier_timeout= + [NET] Specifies amount of time (in seconds) that + netpoll should wait for a carrier. By default netpoll + waits 4 seconds. + no387 [BUGS=X86-32] Tells the kernel to use the 387 maths emulation library even if a 387 maths coprocessor is present. diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 9675f312830..3afe381e24a 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -9,6 +9,7 @@ * Copyright (C) 2002 Red Hat, Inc. */ +#include #include #include #include @@ -50,6 +51,9 @@ static atomic_t trapped; static void zap_completion_queue(void); static void arp_reply(struct sk_buff *skb); +static unsigned int carrier_timeout = 4; +module_param(carrier_timeout, uint, 0644); + static void queue_process(struct work_struct *work) { struct netpoll_info *npinfo = @@ -732,7 +736,7 @@ int netpoll_setup(struct netpoll *np) } atleast = jiffies + HZ/10; - atmost = jiffies + 4*HZ; + atmost = jiffies + carrier_timeout * HZ; while (!netif_carrier_ok(ndev)) { if (time_after(jiffies, atmost)) { printk(KERN_NOTICE -- cgit v1.2.3-70-g09d2 From fa5ec8a1f66f3c2a3af723abcf8085509c9ee682 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Tue, 7 Jul 2009 00:14:14 -0700 Subject: slub: add option to disable higher order debugging slabs When debugging is enabled, slub requires that additional metadata be stored in slabs for certain options: SLAB_RED_ZONE, SLAB_POISON, and SLAB_STORE_USER. Consequently, it may require that the minimum possible slab order needed to allocate a single object be greater when using these options. The most notable example is for objects that are PAGE_SIZE bytes in size. Higher minimum slab orders may cause page allocation failures when oom or under heavy fragmentation. This patch adds a new slub_debug option, which disables debugging by default for caches that would have resulted in higher minimum orders: slub_debug=O When this option is used on systems with 4K pages, kmalloc-4096, for example, will not have debugging enabled by default even if CONFIG_SLUB_DEBUG_ON is defined because it would have resulted in a order-1 minimum slab order. Reported-by: Larry Finger Tested-by: Larry Finger Cc: Christoph Lameter Signed-off-by: David Rientjes Signed-off-by: Pekka Enberg --- Documentation/vm/slub.txt | 10 ++++++++++ mm/slub.c | 41 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 3 deletions(-) (limited to 'Documentation') diff --git a/Documentation/vm/slub.txt b/Documentation/vm/slub.txt index bb1f5c6e28b..510917ff59e 100644 --- a/Documentation/vm/slub.txt +++ b/Documentation/vm/slub.txt @@ -41,6 +41,8 @@ Possible debug options are P Poisoning (object and padding) U User tracking (free and alloc) T Trace (please only use on single slabs) + O Switch debugging off for caches that would have + caused higher minimum slab orders - Switch all debugging off (useful if the kernel is configured with CONFIG_SLUB_DEBUG_ON) @@ -59,6 +61,14 @@ to the dentry cache with slub_debug=F,dentry +Debugging options may require the minimum possible slab order to increase as +a result of storing the metadata (for example, caches with PAGE_SIZE object +sizes). This has a higher liklihood of resulting in slab allocation errors +in low memory situations or if there's high fragmentation of memory. To +switch off debugging for such caches by default, use + + slub_debug=O + In case you forgot to enable debugging on the kernel command line: It is possible to enable debugging manually when the kernel is up. Look at the contents of: diff --git a/mm/slub.c b/mm/slub.c index a9201d83178..466089cd5de 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -141,6 +141,13 @@ #define DEBUG_DEFAULT_FLAGS (SLAB_DEBUG_FREE | SLAB_RED_ZONE | \ SLAB_POISON | SLAB_STORE_USER) +/* + * Debugging flags that require metadata to be stored in the slab, up to + * DEBUG_SIZE in size. + */ +#define DEBUG_SIZE_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER) +#define DEBUG_SIZE (3 * sizeof(void *) + 2 * sizeof(struct track)) + /* * Set of flags that will prevent slab merging */ @@ -326,6 +333,7 @@ static int slub_debug; #endif static char *slub_debug_slabs; +static int disable_higher_order_debug; /* * Object debugging @@ -977,6 +985,15 @@ static int __init setup_slub_debug(char *str) */ goto check_slabs; + if (tolower(*str) == 'o') { + /* + * Avoid enabling debugging on caches if its minimum order + * would increase as a result. + */ + disable_higher_order_debug = 1; + goto out; + } + slub_debug = 0; if (*str == '-') /* @@ -1023,13 +1040,27 @@ static unsigned long kmem_cache_flags(unsigned long objsize, unsigned long flags, const char *name, void (*ctor)(void *)) { + int debug_flags = slub_debug; + /* * Enable debugging if selected on the kernel commandline. */ - if (slub_debug && (!slub_debug_slabs || - strncmp(slub_debug_slabs, name, strlen(slub_debug_slabs)) == 0)) - flags |= slub_debug; + if (debug_flags) { + if (slub_debug_slabs && + strncmp(slub_debug_slabs, name, strlen(slub_debug_slabs))) + goto out; + + /* + * Disable debugging that increases slab size if the minimum + * slab order would have increased as a result. + */ + if (disable_higher_order_debug && + get_order(objsize + DEBUG_SIZE) > get_order(objsize)) + debug_flags &= ~DEBUG_SIZE_FLAGS; + flags |= debug_flags; + } +out: return flags; } #else @@ -1561,6 +1592,10 @@ slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid) "default order: %d, min order: %d\n", s->name, s->objsize, s->size, oo_order(s->oo), oo_order(s->min)); + if (oo_order(s->min) > get_order(s->objsize)) + printk(KERN_WARNING " %s debugging increased min order, use " + "slub_debug=O to disable.\n", s->name); + for_each_online_node(node) { struct kmem_cache_node *n = get_node(s, node); unsigned long nr_slabs; -- cgit v1.2.3-70-g09d2 From 0741241c6b80bfd58417e95de984d60c9e9ef2a0 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 17 Jul 2009 10:13:21 -0700 Subject: connector: make callback argument type explicit The connector documentation states that the argument to the callback function is always a pointer to a struct cn_msg, but rather than encode it in the API itself, it uses a void pointer everywhere. This doesn't make much sense to encode the pointer in documentation as it prevents proper C type checking from occurring and can easily allow people to use the wrong pointer type. So convert the argument type to an explicit struct cn_msg pointer. Signed-off-by: Mike Frysinger Signed-off-by: David S. Miller --- Documentation/connector/cn_test.c | 4 +--- drivers/connector/cn_proc.c | 3 +-- drivers/connector/cn_queue.c | 7 +++++-- drivers/connector/connector.c | 6 +++--- drivers/staging/dst/dcore.c | 3 +-- drivers/video/uvesafb.c | 3 +-- drivers/w1/w1_netlink.c | 3 +-- include/linux/connector.h | 6 +++--- 8 files changed, 16 insertions(+), 19 deletions(-) (limited to 'Documentation') diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c index f688eba8770..50d5ce4899c 100644 --- a/Documentation/connector/cn_test.c +++ b/Documentation/connector/cn_test.c @@ -32,10 +32,8 @@ static char cn_test_name[] = "cn_test"; static struct sock *nls; static struct timer_list cn_test_timer; -void cn_test_callback(void *data) +void cn_test_callback(struct cn_msg *msg) { - struct cn_msg *msg = (struct cn_msg *)data; - printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n", __func__, jiffies, msg->id.idx, msg->id.val, msg->seq, msg->ack, msg->len, (char *)msg->data); diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c index c5afc98e267..85e5dc0431f 100644 --- a/drivers/connector/cn_proc.c +++ b/drivers/connector/cn_proc.c @@ -202,9 +202,8 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack) * cn_proc_mcast_ctl * @data: message sent from userspace via the connector */ -static void cn_proc_mcast_ctl(void *data) +static void cn_proc_mcast_ctl(struct cn_msg *msg) { - struct cn_msg *msg = data; enum proc_cn_mcast_op *mc_op = NULL; int err = 0; diff --git a/drivers/connector/cn_queue.c b/drivers/connector/cn_queue.c index c769ef269fb..d478aefcd3b 100644 --- a/drivers/connector/cn_queue.c +++ b/drivers/connector/cn_queue.c @@ -87,7 +87,9 @@ void cn_queue_wrapper(struct work_struct *work) kfree(d->free); } -static struct cn_callback_entry *cn_queue_alloc_callback_entry(char *name, struct cb_id *id, void (*callback)(void *)) +static struct cn_callback_entry * +cn_queue_alloc_callback_entry(char *name, struct cb_id *id, + void (*callback)(struct cn_msg *)) { struct cn_callback_entry *cbq; @@ -120,7 +122,8 @@ int cn_cb_equal(struct cb_id *i1, struct cb_id *i2) return ((i1->idx == i2->idx) && (i1->val == i2->val)); } -int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *)) +int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, + void (*callback)(struct cn_msg *)) { struct cn_callback_entry *cbq, *__cbq; int found = 0; diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index fd336c5a905..3f45669f5d7 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -269,7 +269,8 @@ static void cn_notify(struct cb_id *id, u32 notify_event) * * May sleep. */ -int cn_add_callback(struct cb_id *id, char *name, void (*callback)(void *)) +int cn_add_callback(struct cb_id *id, char *name, + void (*callback)(struct cn_msg *)) { int err; struct cn_dev *dev = &cdev; @@ -351,9 +352,8 @@ static int cn_ctl_msg_equals(struct cn_ctl_msg *m1, struct cn_ctl_msg *m2) * * Used for notification of a request's processing. */ -static void cn_callback(void *data) +static void cn_callback(struct cn_msg *msg) { - struct cn_msg *msg = data; struct cn_ctl_msg *ctl; struct cn_ctl_entry *ent; u32 size; diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c index fad25b75304..84724187ec3 100644 --- a/drivers/staging/dst/dcore.c +++ b/drivers/staging/dst/dcore.c @@ -846,10 +846,9 @@ static dst_command_func dst_commands[] = { /* * Configuration parser. */ -static void cn_dst_callback(void *data) +static void cn_dst_callback(struct cn_msg *msg) { struct dst_ctl *ctl; - struct cn_msg *msg = data; int err; struct dst_ctl_ack ack; struct dst_node *n = NULL, *tmp; diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index ca5b4643a40..e98baf6916b 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -67,9 +67,8 @@ static DEFINE_MUTEX(uvfb_lock); * find the kernel part of the task struct, copy the registers and * the buffer contents and then complete the task. */ -static void uvesafb_cn_callback(void *data) +static void uvesafb_cn_callback(struct cn_msg *msg) { - struct cn_msg *msg = data; struct uvesafb_task *utask; struct uvesafb_ktask *task; diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index fdf72851c57..52ccb3d3a96 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c @@ -306,9 +306,8 @@ static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rm return error; } -static void w1_cn_callback(void *data) +static void w1_cn_callback(struct cn_msg *msg) { - struct cn_msg *msg = data; struct w1_netlink_msg *m = (struct w1_netlink_msg *)(msg + 1); struct w1_netlink_cmd *cmd; struct w1_slave *sl; diff --git a/include/linux/connector.h b/include/linux/connector.h index b68d27850d5..47ebf416f51 100644 --- a/include/linux/connector.h +++ b/include/linux/connector.h @@ -136,7 +136,7 @@ struct cn_callback_data { void *ddata; void *callback_priv; - void (*callback) (void *); + void (*callback) (struct cn_msg *); void *free; }; @@ -167,11 +167,11 @@ struct cn_dev { struct cn_queue_dev *cbdev; }; -int cn_add_callback(struct cb_id *, char *, void (*callback) (void *)); +int cn_add_callback(struct cb_id *, char *, void (*callback) (struct cn_msg *)); void cn_del_callback(struct cb_id *); int cn_netlink_send(struct cn_msg *, u32, gfp_t); -int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(void *)); +int cn_queue_add_callback(struct cn_queue_dev *dev, char *name, struct cb_id *id, void (*callback)(struct cn_msg *)); void cn_queue_del_callback(struct cn_queue_dev *dev, struct cb_id *id); int queue_cn_work(struct cn_callback_entry *cbq, struct work_struct *work); -- cgit v1.2.3-70-g09d2 From 41144ca3dda6d55b10c46d5b7d86502ccffa1c97 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 17 Jul 2009 10:13:58 -0700 Subject: connector: clean up grammar/style in documentation The grammar in most of this file is slightly off, and some sections are hard to read due to lack of visual clues breaking up related material. Signed-off-by: Mike Frysinger Signed-off-by: David S. Miller --- Documentation/connector/connector.txt | 119 +++++++++++++++++----------------- 1 file changed, 61 insertions(+), 58 deletions(-) (limited to 'Documentation') diff --git a/Documentation/connector/connector.txt b/Documentation/connector/connector.txt index ad6e0ba7b38..81e6bf6ead5 100644 --- a/Documentation/connector/connector.txt +++ b/Documentation/connector/connector.txt @@ -5,10 +5,10 @@ Kernel Connector. Kernel connector - new netlink based userspace <-> kernel space easy to use communication module. -Connector driver adds possibility to connect various agents using -netlink based network. One must register callback and -identifier. When driver receives special netlink message with -appropriate identifier, appropriate callback will be called. +The Connector driver makes it easy to connect various agents using a +netlink based network. One must register a callback and an identifier. +When the driver receives a special netlink message with the appropriate +identifier, the appropriate callback will be called. From the userspace point of view it's quite straightforward: @@ -17,10 +17,10 @@ From the userspace point of view it's quite straightforward: send(); recv(); -But if kernelspace want to use full power of such connections, driver -writer must create special sockets, must know about struct sk_buff -handling... Connector allows any kernelspace agents to use netlink -based networking for inter-process communication in a significantly +But if kernelspace wants to use the full power of such connections, the +driver writer must create special sockets, must know about struct sk_buff +handling, etc... The Connector driver allows any kernelspace agents to use +netlink based networking for inter-process communication in a significantly easier way: int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *)); @@ -32,15 +32,15 @@ struct cb_id __u32 val; }; -idx and val are unique identifiers which must be registered in -connector.h for in-kernel usage. void (*callback) (void *) - is a -callback function which will be called when message with above idx.val -will be received by connector core. Argument for that function must +idx and val are unique identifiers which must be registered in the +connector.h header for in-kernel usage. void (*callback) (void *) is a +callback function which will be called when a message with above idx.val +is received by the connector core. The argument for that function must be dereferenced to struct cn_msg *. struct cn_msg { - struct cb_id id; + struct cb_id id; __u32 seq; __u32 ack; @@ -55,92 +55,95 @@ Connector interfaces. int cn_add_callback(struct cb_id *id, char *name, void (*callback) (void *)); -Registers new callback with connector core. + Registers new callback with connector core. -struct cb_id *id - unique connector's user identifier. - It must be registered in connector.h for legal in-kernel users. -char *name - connector's callback symbolic name. -void (*callback) (void *) - connector's callback. + struct cb_id *id - unique connector's user identifier. + It must be registered in connector.h for legal in-kernel users. + char *name - connector's callback symbolic name. + void (*callback) (void *) - connector's callback. Argument must be dereferenced to struct cn_msg *. + void cn_del_callback(struct cb_id *id); -Unregisters new callback with connector core. + Unregisters new callback with connector core. + + struct cb_id *id - unique connector's user identifier. -struct cb_id *id - unique connector's user identifier. int cn_netlink_send(struct cn_msg *msg, u32 __groups, int gfp_mask); -Sends message to the specified groups. It can be safely called from -softirq context, but may silently fail under strong memory pressure. -If there are no listeners for given group -ESRCH can be returned. + Sends message to the specified groups. It can be safely called from + softirq context, but may silently fail under strong memory pressure. + If there are no listeners for given group -ESRCH can be returned. -struct cn_msg * - message header(with attached data). -u32 __group - destination group. + struct cn_msg * - message header(with attached data). + u32 __group - destination group. If __group is zero, then appropriate group will be searched through all registered connector users, and message will be delivered to the group which was created for user with the same ID as in msg. If __group is not zero, then message will be delivered to the specified group. -int gfp_mask - GFP mask. + int gfp_mask - GFP mask. -Note: When registering new callback user, connector core assigns -netlink group to the user which is equal to it's id.idx. + Note: When registering new callback user, connector core assigns + netlink group to the user which is equal to it's id.idx. /*****************************************/ Protocol description. /*****************************************/ -Current offers transport layer with fixed header. Recommended -protocol which uses such header is following: +The current framework offers a transport layer with fixed headers. The +recommended protocol which uses such a header is as following: msg->seq and msg->ack are used to determine message genealogy. When -someone sends message it puts there locally unique sequence and random -acknowledge numbers. Sequence number may be copied into +someone sends a message, they use a locally unique sequence and random +acknowledge number. The sequence number may be copied into nlmsghdr->nlmsg_seq too. -Sequence number is incremented with each message to be sent. +The sequence number is incremented with each message sent. -If we expect reply to our message, then sequence number in received -message MUST be the same as in original message, and acknowledge -number MUST be the same + 1. +If you expect a reply to the message, then the sequence number in the +received message MUST be the same as in the original message, and the +acknowledge number MUST be the same + 1. -If we receive message and it's sequence number is not equal to one we -are expecting, then it is new message. If we receive message and it's -sequence number is the same as one we are expecting, but it's -acknowledge is not equal acknowledge number in original message + 1, -then it is new message. +If we receive a message and its sequence number is not equal to one we +are expecting, then it is a new message. If we receive a message and +its sequence number is the same as one we are expecting, but its +acknowledge is not equal to the acknowledge number in the original +message + 1, then it is a new message. -Obviously, protocol header contains above id. +Obviously, the protocol header contains the above id. -connector allows event notification in the following form: kernel +The connector allows event notification in the following form: kernel driver or userspace process can ask connector to notify it when -selected id's will be turned on or off(registered or unregistered it's -callback). It is done by sending special command to connector -driver(it also registers itself with id={-1, -1}). +selected ids will be turned on or off (registered or unregistered its +callback). It is done by sending a special command to the connector +driver (it also registers itself with id={-1, -1}). -As example of usage Documentation/connector now contains cn_test.c - -testing module which uses connector to request notification and to -send messages. +As example of this usage can be found in the cn_test.c module which +uses the connector to request notification and to send messages. /*****************************************/ Reliability. /*****************************************/ -Netlink itself is not reliable protocol, that means that messages can +Netlink itself is not a reliable protocol. That means that messages can be lost due to memory pressure or process' receiving queue overflowed, -so caller is warned must be prepared. That is why struct cn_msg [main -connector's message header] contains u32 seq and u32 ack fields. +so caller is warned that it must be prepared. That is why the struct +cn_msg [main connector's message header] contains u32 seq and u32 ack +fields. /*****************************************/ Userspace usage. /*****************************************/ + 2.6.14 has a new netlink socket implementation, which by default does not -allow to send data to netlink groups other than 1. -So, if to use netlink socket (for example using connector) -with different group number userspace application must subscribe to -that group. It can be achieved by following pseudocode: +allow people to send data to netlink groups other than 1. +So, if you wish to use a netlink socket (for example using connector) +with a different group number, the userspace application must subscribe to +that group first. It can be achieved by the following pseudocode: s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR); @@ -160,8 +163,8 @@ if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) { } Where 270 above is SOL_NETLINK, and 1 is a NETLINK_ADD_MEMBERSHIP socket -option. To drop multicast subscription one should call above socket option -with NETLINK_DROP_MEMBERSHIP parameter which is defined as 0. +option. To drop a multicast subscription, one should call the above socket +option with the NETLINK_DROP_MEMBERSHIP parameter which is defined as 0. 2.6.14 netlink code only allows to select a group which is less or equal to the maximum group number, which is used at netlink_kernel_create() time. -- cgit v1.2.3-70-g09d2 From 37cf2b8d1622897cf57e70cdab9eba57feb5ff6c Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Fri, 17 Jul 2009 10:14:26 -0700 Subject: connector: get test code working by default The connector test code currently does not work out of the box. This is because it uses a connector id that is above the registered limit. So rather than force people to stumble through undocumented code wondering why it isn't working, have the test code use one of the "private" ids by default. While I'm in here, clean up the code (kernel and user app) so that it's a bit more user friendly and verbose in significant things that it does. Terse test code wastes people time as they simply enumerate it with all the same kind of debug messages to get a better feel of what code is running at any time. Signed-off-by: Mike Frysinger Signed-off-by: David S. Miller --- Documentation/connector/Makefile | 5 ++++ Documentation/connector/cn_test.c | 31 ++++++++++++-------- Documentation/connector/ucon.c | 62 +++++++++++++++++++++++++++++++++------ 3 files changed, 76 insertions(+), 22 deletions(-) (limited to 'Documentation') diff --git a/Documentation/connector/Makefile b/Documentation/connector/Makefile index 8df1a7285a0..d98e4df98e2 100644 --- a/Documentation/connector/Makefile +++ b/Documentation/connector/Makefile @@ -9,3 +9,8 @@ hostprogs-y := ucon always := $(hostprogs-y) HOSTCFLAGS_ucon.o += -I$(objtree)/usr/include + +all: modules + +modules clean: + $(MAKE) -C ../.. SUBDIRS=$(PWD) $@ diff --git a/Documentation/connector/cn_test.c b/Documentation/connector/cn_test.c index 50d5ce4899c..6e73190af0b 100644 --- a/Documentation/connector/cn_test.c +++ b/Documentation/connector/cn_test.c @@ -19,6 +19,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#define pr_fmt(fmt) "cn_test: " fmt + #include #include #include @@ -27,16 +29,17 @@ #include -static struct cb_id cn_test_id = { 0x123, 0x456 }; +static struct cb_id cn_test_id = { CN_NETLINK_USERS + 3, 0x456 }; static char cn_test_name[] = "cn_test"; static struct sock *nls; static struct timer_list cn_test_timer; -void cn_test_callback(struct cn_msg *msg) +static void cn_test_callback(struct cn_msg *msg) { - printk("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n", - __func__, jiffies, msg->id.idx, msg->id.val, - msg->seq, msg->ack, msg->len, (char *)msg->data); + pr_info("%s: %lu: idx=%x, val=%x, seq=%u, ack=%u, len=%d: %s.\n", + __func__, jiffies, msg->id.idx, msg->id.val, + msg->seq, msg->ack, msg->len, + msg->len ? (char *)msg->data : ""); } /* @@ -61,9 +64,7 @@ static int cn_test_want_notify(void) skb = alloc_skb(size, GFP_ATOMIC); if (!skb) { - printk(KERN_ERR "Failed to allocate new skb with size=%u.\n", - size); - + pr_err("failed to allocate new skb with size=%u\n", size); return -ENOMEM; } @@ -112,12 +113,12 @@ static int cn_test_want_notify(void) //netlink_broadcast(nls, skb, 0, ctl->group, GFP_ATOMIC); netlink_unicast(nls, skb, 0, 0); - printk(KERN_INFO "Request was sent. Group=0x%x.\n", ctl->group); + pr_info("request was sent: group=0x%x\n", ctl->group); return 0; nlmsg_failure: - printk(KERN_ERR "Failed to send %u.%u\n", msg->seq, msg->ack); + pr_err("failed to send %u.%u\n", msg->seq, msg->ack); kfree_skb(skb); return -EINVAL; } @@ -129,6 +130,8 @@ static void cn_test_timer_func(unsigned long __data) struct cn_msg *m; char data[32]; + pr_debug("%s: timer fired with data %lu\n", __func__, __data); + m = kzalloc(sizeof(*m) + sizeof(data), GFP_ATOMIC); if (m) { @@ -148,7 +151,7 @@ static void cn_test_timer_func(unsigned long __data) cn_test_timer_counter++; - mod_timer(&cn_test_timer, jiffies + HZ); + mod_timer(&cn_test_timer, jiffies + msecs_to_jiffies(1000)); } static int cn_test_init(void) @@ -166,8 +169,10 @@ static int cn_test_init(void) } setup_timer(&cn_test_timer, cn_test_timer_func, 0); - cn_test_timer.expires = jiffies + HZ; - add_timer(&cn_test_timer); + mod_timer(&cn_test_timer, jiffies + msecs_to_jiffies(1000)); + + pr_info("initialized with id={%u.%u}\n", + cn_test_id.idx, cn_test_id.val); return 0; diff --git a/Documentation/connector/ucon.c b/Documentation/connector/ucon.c index d738cde2a8d..a8e4d5885ad 100644 --- a/Documentation/connector/ucon.c +++ b/Documentation/connector/ucon.c @@ -30,18 +30,24 @@ #include +#include #include #include #include #include #include #include +#include #include #define DEBUG #define NETLINK_CONNECTOR 11 +/* Hopefully your userspace connector.h matches this kernel */ +#define CN_TEST_IDX CN_NETLINK_USERS + 3 +#define CN_TEST_VAL 0x456 + #ifdef DEBUG #define ulog(f, a...) fprintf(stdout, f, ##a) #else @@ -83,6 +89,25 @@ static int netlink_send(int s, struct cn_msg *msg) return err; } +static void usage(void) +{ + printf( + "Usage: ucon [options] [output file]\n" + "\n" + "\t-h\tthis help screen\n" + "\t-s\tsend buffers to the test module\n" + "\n" + "The default behavior of ucon is to subscribe to the test module\n" + "and wait for state messages. Any ones received are dumped to the\n" + "specified output file (or stdout). The test module is assumed to\n" + "have an id of {%u.%u}\n" + "\n" + "If you get no output, then verify the cn_test module id matches\n" + "the expected id above.\n" + , CN_TEST_IDX, CN_TEST_VAL + ); +} + int main(int argc, char *argv[]) { int s; @@ -94,17 +119,34 @@ int main(int argc, char *argv[]) FILE *out; time_t tm; struct pollfd pfd; + bool send_msgs = false; - if (argc < 2) - out = stdout; - else { - out = fopen(argv[1], "a+"); + while ((s = getopt(argc, argv, "hs")) != -1) { + switch (s) { + case 's': + send_msgs = true; + break; + + case 'h': + usage(); + return 0; + + default: + /* getopt() outputs an error for us */ + usage(); + return 1; + } + } + + if (argc != optind) { + out = fopen(argv[optind], "a+"); if (!out) { ulog("Unable to open %s for writing: %s\n", argv[1], strerror(errno)); out = stdout; } - } + } else + out = stdout; memset(buf, 0, sizeof(buf)); @@ -115,9 +157,11 @@ int main(int argc, char *argv[]) } l_local.nl_family = AF_NETLINK; - l_local.nl_groups = 0x123; /* bitmask of requested groups */ + l_local.nl_groups = -1; /* bitmask of requested groups */ l_local.nl_pid = 0; + ulog("subscribing to %u.%u\n", CN_TEST_IDX, CN_TEST_VAL); + if (bind(s, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl)) == -1) { perror("bind"); close(s); @@ -130,15 +174,15 @@ int main(int argc, char *argv[]) setsockopt(s, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &on, sizeof(on)); } #endif - if (0) { + if (send_msgs) { int i, j; memset(buf, 0, sizeof(buf)); data = (struct cn_msg *)buf; - data->id.idx = 0x123; - data->id.val = 0x456; + data->id.idx = CN_TEST_IDX; + data->id.val = CN_TEST_VAL; data->seq = seq++; data->ack = 0; data->len = 0; -- cgit v1.2.3-70-g09d2 From 3162534069597e34dd0ac9eb711be8dc23835ae7 Mon Sep 17 00:00:00 2001 From: Joseph Cihula Date: Tue, 30 Jun 2009 19:30:59 -0700 Subject: x86, intel_txt: Intel TXT boot support This patch adds kernel configuration and boot support for Intel Trusted Execution Technology (Intel TXT). Intel's technology for safer computing, Intel Trusted Execution Technology (Intel TXT), defines platform-level enhancements that provide the building blocks for creating trusted platforms. Intel TXT was formerly known by the code name LaGrande Technology (LT). Intel TXT in Brief: o Provides dynamic root of trust for measurement (DRTM) o Data protection in case of improper shutdown o Measurement and verification of launched environment Intel TXT is part of the vPro(TM) brand and is also available some non-vPro systems. It is currently available on desktop systems based on the Q35, X38, Q45, and Q43 Express chipsets (e.g. Dell Optiplex 755, HP dc7800, etc.) and mobile systems based on the GM45, PM45, and GS45 Express chipsets. For more information, see http://www.intel.com/technology/security/. This site also has a link to the Intel TXT MLE Developers Manual, which has been updated for the new released platforms. A much more complete description of how these patches support TXT, how to configure a system for it, etc. is in the Documentation/intel_txt.txt file in this patch. This patch provides the TXT support routines for complete functionality, documentation for TXT support and for the changes to the boot_params structure, and boot detection of a TXT launch. Attempts to shutdown (reboot, Sx) the system will result in platform resets; subsequent patches will support these shutdown modes properly. Documentation/intel_txt.txt | 210 +++++++++++++++++++++ Documentation/x86/zero-page.txt | 1 arch/x86/include/asm/bootparam.h | 3 arch/x86/include/asm/fixmap.h | 3 arch/x86/include/asm/tboot.h | 197 ++++++++++++++++++++ arch/x86/kernel/Makefile | 1 arch/x86/kernel/setup.c | 4 arch/x86/kernel/tboot.c | 379 +++++++++++++++++++++++++++++++++++++++ security/Kconfig | 30 +++ 9 files changed, 827 insertions(+), 1 deletion(-) Signed-off-by: Joseph Cihula Signed-off-by: Shane Wang Signed-off-by: Gang Wei Signed-off-by: H. Peter Anvin --- Documentation/intel_txt.txt | 210 ++++++++++++++++++++++ Documentation/x86/zero-page.txt | 1 + arch/x86/include/asm/bootparam.h | 3 +- arch/x86/include/asm/fixmap.h | 3 + arch/x86/include/asm/tboot.h | 197 ++++++++++++++++++++ arch/x86/kernel/Makefile | 1 + arch/x86/kernel/setup.c | 4 + arch/x86/kernel/tboot.c | 379 +++++++++++++++++++++++++++++++++++++++ security/Kconfig | 30 ++++ 9 files changed, 827 insertions(+), 1 deletion(-) create mode 100644 Documentation/intel_txt.txt create mode 100644 arch/x86/include/asm/tboot.h create mode 100644 arch/x86/kernel/tboot.c (limited to 'Documentation') diff --git a/Documentation/intel_txt.txt b/Documentation/intel_txt.txt new file mode 100644 index 00000000000..f40a1f03001 --- /dev/null +++ b/Documentation/intel_txt.txt @@ -0,0 +1,210 @@ +Intel(R) TXT Overview: +===================== + +Intel's technology for safer computing, Intel(R) Trusted Execution +Technology (Intel(R) TXT), defines platform-level enhancements that +provide the building blocks for creating trusted platforms. + +Intel TXT was formerly known by the code name LaGrande Technology (LT). + +Intel TXT in Brief: +o Provides dynamic root of trust for measurement (DRTM) +o Data protection in case of improper shutdown +o Measurement and verification of launched environment + +Intel TXT is part of the vPro(TM) brand and is also available some +non-vPro systems. It is currently available on desktop systems +based on the Q35, X38, Q45, and Q43 Express chipsets (e.g. Dell +Optiplex 755, HP dc7800, etc.) and mobile systems based on the GM45, +PM45, and GS45 Express chipsets. + +For more information, see http://www.intel.com/technology/security/. +This site also has a link to the Intel TXT MLE Developers Manual, +which has been updated for the new released platforms. + +Intel TXT has been presented at various events over the past few +years, some of which are: + LinuxTAG 2008: + http://www.linuxtag.org/2008/en/conf/events/vp-donnerstag/ + details.html?talkid=110 + TRUST2008: + http://www.trust2008.eu/downloads/Keynote-Speakers/ + 3_David-Grawrock_The-Front-Door-of-Trusted-Computing.pdf + IDF 2008, Shanghai: + http://inteldeveloperforum.com.edgesuite.net/shanghai_2008/ + aep/PROS003/index.html + IDFs 2006, 2007 (I'm not sure if/where they are online) + +Trusted Boot Project Overview: +============================= + +Trusted Boot (tboot) is an open source, pre- kernel/VMM module that +uses Intel TXT to perform a measured and verified launch of an OS +kernel/VMM. + +It is hosted on SourceForge at http://sourceforge.net/projects/tboot. +The mercurial source repo is available at http://www.bughost.org/ +repos.hg/tboot.hg. + +Tboot currently supports launching Xen (open source VMM/hypervisor +w/ TXT support since v3.2), and now Linux kernels. + + +Value Proposition for Linux or "Why should you care?" +===================================================== + +While there are many products and technologies that attempt to +measure or protect the integrity of a running kernel, they all +assume the kernel is "good" to begin with. The Integrity +Measurement Architecture (IMA) and Linux Integrity Module interface +are examples of such solutions. + +To get trust in the initial kernel without using Intel TXT, a +static root of trust must be used. This bases trust in BIOS +starting at system reset and requires measurement of all code +executed between system reset through the completion of the kernel +boot as well as data objects used by that code. In the case of a +Linux kernel, this means all of BIOS, any option ROMs, the +bootloader and the boot config. In practice, this is a lot of +code/data, much of which is subject to change from boot to boot +(e.g. changing NICs may change option ROMs). Without reference +hashes, these measurement changes are difficult to assess or +confirm as benign. This process also does not provide DMA +protection, memory configuration/alias checks and locks, crash +protection, or policy support. + +By using the hardware-based root of trust that Intel TXT provides, +many of these issues can be mitigated. Specifically: many +pre-launch components can be removed from the trust chain, DMA +protection is provided to all launched components, a large number +of platform configuration checks are performed and values locked, +protection is provided for any data in the event of an improper +shutdown, and there is support for policy-based execution/verification. +This provides a more stable measurement and a higher assurance of +system configuration and initial state than would be otherwise +possible. Since the tboot project is open source, source code for +almost all parts of the trust chain is available (excepting SMM and +Intel-provided firmware). + +How Does it Work? +================= + +o Tboot is an executable that is launched by the bootloader as + the "kernel" (the binary the bootloader executes). +o It performs all of the work necessary to determine if the + platform supports Intel TXT and, if so, executes the GETSEC[SENTER] + processor instruction that initiates the dynamic root of trust. + - If tboot determines that the system does not support Intel TXT + or is not configured correctly (e.g. the SINIT AC Module was + incorrect), it will directly launch the kernel with no changes + to any state. + - Tboot will output various information about its progress to the + terminal, serial port, and/or an in-memory log; the output + locations can be configured with a command line switch. +o The GETSEC[SENTER] instruction will return control to tboot and + tboot then verifies certain aspects of the environment (e.g. TPM NV + lock, e820 table does not have invalid entries, etc.). +o It will wake the APs from the special sleep state the GETSEC[SENTER] + instruction had put them in and place them into a wait-for-SIPI + state. + - Because the processors will not respond to an INIT or SIPI when + in the TXT environment, it is necessary to create a small VT-x + guest for the APs. When they run in this guest, they will + simply wait for the INIT-SIPI-SIPI sequence, which will cause + VMEXITs, and then disable VT and jump to the SIPI vector. This + approach seemed like a better choice than having to insert + special code into the kernel's MP wakeup sequence. +o Tboot then applies an (optional) user-defined launch policy to + verify the kernel and initrd. + - This policy is rooted in TPM NV and is described in the tboot + project. The tboot project also contains code for tools to + create and provision the policy. + - Policies are completely under user control and if not present + then any kernel will be launched. + - Policy action is flexible and can include halting on failures + or simply logging them and continuing. +o Tboot adjusts the e820 table provided by the bootloader to reserve + its own location in memory as well as to reserve certain other + TXT-related regions. +o As part of it's launch, tboot DMA protects all of RAM (using the + VT-d PMRs). Thus, the kernel must be booted with 'intel_iommu=on' + in order to remove this blanket protection and use VT-d's + page-level protection. +o Tboot will populate a shared page with some data about itself and + pass this to the Linux kernel as it transfers control. + - The location of the shared page is passed via the boot_params + struct as a physical address. +o The kernel will look for the tboot shared page address and, if it + exists, map it. +o As one of the checks/protections provided by TXT, it makes a copy + of the VT-d DMARs in a DMA-protected region of memory and verifies + them for correctness. The VT-d code will detect if the kernel was + launched with tboot and use this copy instead of the one in the + ACPI table. +o At this point, tboot and TXT are out of the picture until a + shutdown (S) +o In order to put a system into any of the sleep states after a TXT + launch, TXT must first be exited. This is to prevent attacks that + attempt to crash the system to gain control on reboot and steal + data left in memory. + - The kernel will perform all of its sleep preparation and + populate the shared page with the ACPI data needed to put the + platform in the desired sleep state. + - Then the kernel jumps into tboot via the vector specified in the + shared page. + - Tboot will clean up the environment and disable TXT, then use the + kernel-provided ACPI information to actually place the platform + into the desired sleep state. + - In the case of S3, tboot will also register itself as the resume + vector. This is necessary because it must re-establish the + measured environment upon resume. Once the TXT environment + has been restored, it will restore the TPM PCRs and then + transfer control back to the kernel's S3 resume vector. + In order to preserve system integrity across S3, the kernel + provides tboot with a set of memory ranges (kernel + code/data/bss, S3 resume code, and AP trampoline) that tboot + will calculate a MAC (message authentication code) over and then + seal with the TPM. On resume and once the measured environment + has been re-established, tboot will re-calculate the MAC and + verify it against the sealed value. Tboot's policy determines + what happens if the verification fails. + +That's pretty much it for TXT support. + + +Configuring the System: +====================== + +This code works with 32bit, 32bit PAE, and 64bit (x86_64) kernels. + +In BIOS, the user must enable: TPM, TXT, VT-x, VT-d. Not all BIOSes +allow these to be individually enabled/disabled and the screens in +which to find them are BIOS-specific. + +grub.conf needs to be modified as follows: + title Linux 2.6.29-tip w/ tboot + root (hd0,0) + kernel /tboot.gz logging=serial,vga,memory + module /vmlinuz-2.6.29-tip intel_iommu=on ro + root=LABEL=/ rhgb console=ttyS0,115200 3 + module /initrd-2.6.29-tip.img + module /Q35_SINIT_17.BIN + +The kernel option for enabling Intel TXT support is found under the +Security top-level menu and is called "Enable Intel(R) Trusted +Execution Technology (TXT)". It is marked as EXPERIMENTAL and +depends on the generic x86 support (to allow maximum flexibility in +kernel build options), since the tboot code will detect whether the +platform actually supports Intel TXT and thus whether any of the +kernel code is executed. + +The Q35_SINIT_17.BIN file is what Intel TXT refers to as an +Authenticated Code Module. It is specific to the chipset in the +system and can also be found on the Trusted Boot site. It is an +(unencrypted) module signed by Intel that is used as part of the +DRTM process to verify and configure the system. It is signed +because it operates at a higher privilege level in the system than +any other macrocode and its correct operation is critical to the +establishment of the DRTM. The process for determining the correct +SINIT ACM for a system is documented in the SINIT-guide.txt file +that is on the tboot SourceForge site under the SINIT ACM downloads. diff --git a/Documentation/x86/zero-page.txt b/Documentation/x86/zero-page.txt index 4f913857b8a..feb37e17701 100644 --- a/Documentation/x86/zero-page.txt +++ b/Documentation/x86/zero-page.txt @@ -12,6 +12,7 @@ Offset Proto Name Meaning 000/040 ALL screen_info Text mode or frame buffer information (struct screen_info) 040/014 ALL apm_bios_info APM BIOS information (struct apm_bios_info) +058/008 ALL tboot_addr Physical address of tboot shared page 060/010 ALL ist_info Intel SpeedStep (IST) BIOS support information (struct ist_info) 080/010 ALL hd0_info hd0 disk parameter, OBSOLETE!! diff --git a/arch/x86/include/asm/bootparam.h b/arch/x86/include/asm/bootparam.h index 1724e8de317..6ca20218dd7 100644 --- a/arch/x86/include/asm/bootparam.h +++ b/arch/x86/include/asm/bootparam.h @@ -85,7 +85,8 @@ struct efi_info { struct boot_params { struct screen_info screen_info; /* 0x000 */ struct apm_bios_info apm_bios_info; /* 0x040 */ - __u8 _pad2[12]; /* 0x054 */ + __u8 _pad2[4]; /* 0x054 */ + __u64 tboot_addr; /* 0x058 */ struct ist_info ist_info; /* 0x060 */ __u8 _pad3[16]; /* 0x070 */ __u8 hd0_info[16]; /* obsolete! */ /* 0x080 */ diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h index 7b2d71df39a..14f9890eb49 100644 --- a/arch/x86/include/asm/fixmap.h +++ b/arch/x86/include/asm/fixmap.h @@ -131,6 +131,9 @@ enum fixed_addresses { #endif #ifdef CONFIG_X86_32 FIX_WP_TEST, +#endif +#ifdef CONFIG_INTEL_TXT + FIX_TBOOT_BASE, #endif __end_of_fixed_addresses }; diff --git a/arch/x86/include/asm/tboot.h b/arch/x86/include/asm/tboot.h new file mode 100644 index 00000000000..b13929d4e5f --- /dev/null +++ b/arch/x86/include/asm/tboot.h @@ -0,0 +1,197 @@ +/* + * tboot.h: shared data structure with tboot and kernel and functions + * used by kernel for runtime support of Intel(R) Trusted + * Execution Technology + * + * Copyright (c) 2006-2009, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#ifndef _ASM_TBOOT_H +#define _ASM_TBOOT_H + +#include + +/* these must have the values from 0-5 in this order */ +enum { + TB_SHUTDOWN_REBOOT = 0, + TB_SHUTDOWN_S5, + TB_SHUTDOWN_S4, + TB_SHUTDOWN_S3, + TB_SHUTDOWN_HALT, + TB_SHUTDOWN_WFS +}; + +#ifdef CONFIG_INTEL_TXT + +/* used to communicate between tboot and the launched kernel */ + +#define TB_KEY_SIZE 64 /* 512 bits */ + +#define MAX_TB_MAC_REGIONS 32 + +struct tboot_mac_region { + u64 start; /* must be 64 byte -aligned */ + u32 size; /* must be 64 byte -granular */ +} __packed; + +/* GAS - Generic Address Structure (ACPI 2.0+) */ +struct tboot_acpi_generic_address { + u8 space_id; + u8 bit_width; + u8 bit_offset; + u8 access_width; + u64 address; +} __packed; + +/* + * combines Sx info from FADT and FACS tables per ACPI 2.0+ spec + * (http://www.acpi.info/) + */ +struct tboot_acpi_sleep_info { + struct tboot_acpi_generic_address pm1a_cnt_blk; + struct tboot_acpi_generic_address pm1b_cnt_blk; + struct tboot_acpi_generic_address pm1a_evt_blk; + struct tboot_acpi_generic_address pm1b_evt_blk; + u16 pm1a_cnt_val; + u16 pm1b_cnt_val; + u64 wakeup_vector; + u32 vector_width; + u64 kernel_s3_resume_vector; +} __packed; + +/* + * shared memory page used for communication between tboot and kernel + */ +struct tboot { + /* + * version 3+ fields: + */ + + /* TBOOT_UUID */ + u8 uuid[16]; + + /* version number: 5 is current */ + u32 version; + + /* physical addr of tb_log_t log */ + u32 log_addr; + + /* + * physical addr of entry point for tboot shutdown and + * type of shutdown (TB_SHUTDOWN_*) being requested + */ + u32 shutdown_entry; + u32 shutdown_type; + + /* kernel-specified ACPI info for Sx shutdown */ + struct tboot_acpi_sleep_info acpi_sinfo; + + /* tboot location in memory (physical) */ + u32 tboot_base; + u32 tboot_size; + + /* memory regions (phys addrs) for tboot to MAC on S3 */ + u8 num_mac_regions; + struct tboot_mac_region mac_regions[MAX_TB_MAC_REGIONS]; + + + /* + * version 4+ fields: + */ + + /* symmetric key for use by kernel; will be encrypted on S3 */ + u8 s3_key[TB_KEY_SIZE]; + + + /* + * version 5+ fields: + */ + + /* used to 4byte-align num_in_wfs */ + u8 reserved_align[3]; + + /* number of processors in wait-for-SIPI */ + u32 num_in_wfs; +} __packed; + +/* + * UUID for tboot data struct to facilitate matching + * defined as {663C8DFF-E8B3-4b82-AABF-19EA4D057A08} by tboot, which is + * represented as {} in the char array used here + */ +#define TBOOT_UUID {0xff, 0x8d, 0x3c, 0x66, 0xb3, 0xe8, 0x82, 0x4b, 0xbf,\ + 0xaa, 0x19, 0xea, 0x4d, 0x5, 0x7a, 0x8} + +extern struct tboot *tboot; + +static inline int tboot_enabled(void) +{ + return tboot != NULL; +} + +extern void tboot_probe(void); +extern void tboot_create_trampoline(void); +extern void tboot_shutdown(u32 shutdown_type); +extern void tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control); +extern int tboot_wait_for_aps(int num_aps); +extern struct acpi_table_header *tboot_get_dmar_table( + struct acpi_table_header *dmar_tbl); +extern int tboot_force_iommu(void); + +#else /* CONFIG_INTEL_TXT */ + +static inline int tboot_enabled(void) +{ + return 0; +} + +static inline void tboot_probe(void) +{ +} + +static inline void tboot_create_trampoline(void) +{ +} + +static inline void tboot_shutdown(u32 shutdown_type) +{ +} + +static inline void tboot_sleep(u8 sleep_state, u32 pm1a_control, + u32 pm1b_control) +{ +} + +static inline int tboot_wait_for_aps(int num_aps) +{ + return 0; +} + +static inline struct acpi_table_header *tboot_get_dmar_table( + struct acpi_table_header *dmar_tbl) +{ + return dmar_tbl; +} + +static inline int tboot_force_iommu(void) +{ + return 0; +} + +#endif /* !CONFIG_INTEL_TXT */ + +#endif /* _ASM_TBOOT_H */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 430d5b24af7..832cb838cb4 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -52,6 +52,7 @@ obj-$(CONFIG_X86_DS_SELFTEST) += ds_selftest.o obj-$(CONFIG_X86_32) += tls.o obj-$(CONFIG_IA32_EMULATION) += tls.o obj-y += step.o +obj-$(CONFIG_INTEL_TXT) += tboot.o obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-y += cpu/ obj-y += acpi/ diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index de2cab13284..80d6e9e3248 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -145,6 +145,8 @@ struct boot_params __initdata boot_params; struct boot_params boot_params; #endif +#include + /* * Machine setup.. */ @@ -964,6 +966,8 @@ void __init setup_arch(char **cmdline_p) paravirt_pagetable_setup_done(swapper_pg_dir); paravirt_post_allocator_init(); + tboot_probe(); + #ifdef CONFIG_X86_64 map_vsyscall(); #endif diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c new file mode 100644 index 00000000000..263591afd29 --- /dev/null +++ b/arch/x86/kernel/tboot.c @@ -0,0 +1,379 @@ +/* + * tboot.c: main implementation of helper functions used by kernel for + * runtime support of Intel(R) Trusted Execution Technology + * + * Copyright (c) 2006-2009, Intel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "acpi/realmode/wakeup.h" + +/* Global pointer to shared data; NULL means no measured launch. */ +struct tboot *tboot __read_mostly; + +/* timeout for APs (in secs) to enter wait-for-SIPI state during shutdown */ +#define AP_WAIT_TIMEOUT 1 + +#undef pr_fmt +#define pr_fmt(fmt) "tboot: " fmt + +static u8 tboot_uuid[16] __initdata = TBOOT_UUID; + +void __init tboot_probe(void) +{ + /* Look for valid page-aligned address for shared page. */ + if (!boot_params.tboot_addr) + return; + /* + * also verify that it is mapped as we expect it before calling + * set_fixmap(), to reduce chance of garbage value causing crash + */ + if (!e820_any_mapped(boot_params.tboot_addr, + boot_params.tboot_addr, E820_RESERVED)) { + pr_warning("non-0 tboot_addr but it is not of type E820_RESERVED\n"); + return; + } + + /* only a natively booted kernel should be using TXT */ + if (paravirt_enabled()) { + pr_warning("non-0 tboot_addr but pv_ops is enabled\n"); + return; + } + + /* Map and check for tboot UUID. */ + set_fixmap(FIX_TBOOT_BASE, boot_params.tboot_addr); + tboot = (struct tboot *)fix_to_virt(FIX_TBOOT_BASE); + if (memcmp(&tboot_uuid, &tboot->uuid, sizeof(tboot->uuid))) { + pr_warning("tboot at 0x%llx is invalid\n", + boot_params.tboot_addr); + tboot = NULL; + return; + } + if (tboot->version < 5) { + pr_warning("tboot version is invalid: %u\n", tboot->version); + tboot = NULL; + return; + } + + pr_info("found shared page at phys addr 0x%llx:\n", + boot_params.tboot_addr); + pr_debug("version: %d\n", tboot->version); + pr_debug("log_addr: 0x%08x\n", tboot->log_addr); + pr_debug("shutdown_entry: 0x%x\n", tboot->shutdown_entry); + pr_debug("tboot_base: 0x%08x\n", tboot->tboot_base); + pr_debug("tboot_size: 0x%x\n", tboot->tboot_size); +} + +static pgd_t *tboot_pg_dir; +static struct mm_struct tboot_mm = { + .mm_rb = RB_ROOT, + .pgd = swapper_pg_dir, + .mm_users = ATOMIC_INIT(2), + .mm_count = ATOMIC_INIT(1), + .mmap_sem = __RWSEM_INITIALIZER(init_mm.mmap_sem), + .page_table_lock = __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock), + .mmlist = LIST_HEAD_INIT(init_mm.mmlist), + .cpu_vm_mask = CPU_MASK_ALL, +}; + +static inline void switch_to_tboot_pt(void) +{ + write_cr3(virt_to_phys(tboot_pg_dir)); +} + +static int map_tboot_page(unsigned long vaddr, unsigned long pfn, + pgprot_t prot) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + pgd = pgd_offset(&tboot_mm, vaddr); + pud = pud_alloc(&tboot_mm, pgd, vaddr); + if (!pud) + return -1; + pmd = pmd_alloc(&tboot_mm, pud, vaddr); + if (!pmd) + return -1; + pte = pte_alloc_map(&tboot_mm, pmd, vaddr); + if (!pte) + return -1; + set_pte_at(&tboot_mm, vaddr, pte, pfn_pte(pfn, prot)); + pte_unmap(pte); + return 0; +} + +static int map_tboot_pages(unsigned long vaddr, unsigned long start_pfn, + unsigned long nr) +{ + /* Reuse the original kernel mapping */ + tboot_pg_dir = pgd_alloc(&tboot_mm); + if (!tboot_pg_dir) + return -1; + + for (; nr > 0; nr--, vaddr += PAGE_SIZE, start_pfn++) { + if (map_tboot_page(vaddr, start_pfn, PAGE_KERNEL_EXEC)) + return -1; + } + + return 0; +} + +void tboot_create_trampoline(void) +{ + u32 map_base, map_size; + + if (!tboot_enabled()) + return; + + /* Create identity map for tboot shutdown code. */ + map_base = PFN_DOWN(tboot->tboot_base); + map_size = PFN_UP(tboot->tboot_size); + if (map_tboot_pages(map_base << PAGE_SHIFT, map_base, map_size)) + panic("tboot: Error mapping tboot pages (mfns) @ 0x%x, 0x%x\n", map_base, map_size); +} + +static void set_mac_regions(void) +{ + tboot->num_mac_regions = 3; + /* S3 resume code */ + tboot->mac_regions[0].start = PFN_PHYS(PFN_DOWN(acpi_wakeup_address)); + tboot->mac_regions[0].size = PFN_UP(WAKEUP_SIZE) << PAGE_SHIFT; + /* AP trampoline code */ + tboot->mac_regions[1].start = + PFN_PHYS(PFN_DOWN(virt_to_phys(trampoline_base))); + tboot->mac_regions[1].size = PFN_UP(TRAMPOLINE_SIZE) << PAGE_SHIFT; + /* kernel code + data + bss */ + tboot->mac_regions[2].start = PFN_PHYS(PFN_DOWN(virt_to_phys(&_text))); + tboot->mac_regions[2].size = PFN_PHYS(PFN_UP(virt_to_phys(&_end))) - + PFN_PHYS(PFN_DOWN(virt_to_phys(&_text))); +} + +void tboot_shutdown(u32 shutdown_type) +{ + void (*shutdown)(void); + + if (!tboot_enabled()) + return; + + /* + * if we're being called before the 1:1 mapping is set up then just + * return and let the normal shutdown happen; this should only be + * due to very early panic() + */ + if (!tboot_pg_dir) + return; + + /* if this is S3 then set regions to MAC */ + if (shutdown_type == TB_SHUTDOWN_S3) + set_mac_regions(); + + tboot->shutdown_type = shutdown_type; + + switch_to_tboot_pt(); + + shutdown = (void(*)(void))(unsigned long)tboot->shutdown_entry; + shutdown(); + + /* should not reach here */ + while (1) + halt(); +} + +static void tboot_copy_fadt(const struct acpi_table_fadt *fadt) +{ +#define TB_COPY_GAS(tbg, g) \ + tbg.space_id = g.space_id; \ + tbg.bit_width = g.bit_width; \ + tbg.bit_offset = g.bit_offset; \ + tbg.access_width = g.access_width; \ + tbg.address = g.address; + + TB_COPY_GAS(tboot->acpi_sinfo.pm1a_cnt_blk, fadt->xpm1a_control_block); + TB_COPY_GAS(tboot->acpi_sinfo.pm1b_cnt_blk, fadt->xpm1b_control_block); + TB_COPY_GAS(tboot->acpi_sinfo.pm1a_evt_blk, fadt->xpm1a_event_block); + TB_COPY_GAS(tboot->acpi_sinfo.pm1b_evt_blk, fadt->xpm1b_event_block); + + /* + * We need phys addr of waking vector, but can't use virt_to_phys() on + * &acpi_gbl_FACS because it is ioremap'ed, so calc from FACS phys + * addr. + */ + tboot->acpi_sinfo.wakeup_vector = fadt->facs + + offsetof(struct acpi_table_facs, firmware_waking_vector); +} + +void tboot_sleep(u8 sleep_state, u32 pm1a_control, u32 pm1b_control) +{ + static u32 acpi_shutdown_map[ACPI_S_STATE_COUNT] = { + /* S0,1,2: */ -1, -1, -1, + /* S3: */ TB_SHUTDOWN_S3, + /* S4: */ TB_SHUTDOWN_S4, + /* S5: */ TB_SHUTDOWN_S5 }; + + if (!tboot_enabled()) + return; + + tboot_copy_fadt(&acpi_gbl_FADT); + tboot->acpi_sinfo.pm1a_cnt_val = pm1a_control; + tboot->acpi_sinfo.pm1b_cnt_val = pm1b_control; + /* we always use the 32b wakeup vector */ + tboot->acpi_sinfo.vector_width = 32; + tboot->acpi_sinfo.kernel_s3_resume_vector = acpi_wakeup_address; + + if (sleep_state >= ACPI_S_STATE_COUNT || + acpi_shutdown_map[sleep_state] == -1) { + pr_warning("unsupported sleep state 0x%x\n", sleep_state); + return; + } + + tboot_shutdown(acpi_shutdown_map[sleep_state]); +} + +int tboot_wait_for_aps(int num_aps) +{ + unsigned long timeout; + + if (!tboot_enabled()) + return 0; + + timeout = jiffies + AP_WAIT_TIMEOUT*HZ; + while (atomic_read((atomic_t *)&tboot->num_in_wfs) != num_aps && + time_before(jiffies, timeout)) + cpu_relax(); + + return time_before(jiffies, timeout) ? 0 : 1; +} + +/* + * TXT configuration registers (offsets from TXT_{PUB, PRIV}_CONFIG_REGS_BASE) + */ + +#define TXT_PUB_CONFIG_REGS_BASE 0xfed30000 +#define TXT_PRIV_CONFIG_REGS_BASE 0xfed20000 + +/* # pages for each config regs space - used by fixmap */ +#define NR_TXT_CONFIG_PAGES ((TXT_PUB_CONFIG_REGS_BASE - \ + TXT_PRIV_CONFIG_REGS_BASE) >> PAGE_SHIFT) + +/* offsets from pub/priv config space */ +#define TXTCR_HEAP_BASE 0x0300 +#define TXTCR_HEAP_SIZE 0x0308 + +#define SHA1_SIZE 20 + +struct sha1_hash { + u8 hash[SHA1_SIZE]; +}; + +struct sinit_mle_data { + u32 version; /* currently 6 */ + struct sha1_hash bios_acm_id; + u32 edx_senter_flags; + u64 mseg_valid; + struct sha1_hash sinit_hash; + struct sha1_hash mle_hash; + struct sha1_hash stm_hash; + struct sha1_hash lcp_policy_hash; + u32 lcp_policy_control; + u32 rlp_wakeup_addr; + u32 reserved; + u32 num_mdrs; + u32 mdrs_off; + u32 num_vtd_dmars; + u32 vtd_dmars_off; +} __packed; + +struct acpi_table_header *tboot_get_dmar_table(struct acpi_table_header *dmar_tbl) +{ + void *heap_base, *heap_ptr, *config; + + if (!tboot_enabled()) + return dmar_tbl; + + /* + * ACPI tables may not be DMA protected by tboot, so use DMAR copy + * SINIT saved in SinitMleData in TXT heap (which is DMA protected) + */ + + /* map config space in order to get heap addr */ + config = ioremap(TXT_PUB_CONFIG_REGS_BASE, NR_TXT_CONFIG_PAGES * + PAGE_SIZE); + if (!config) + return NULL; + + /* now map TXT heap */ + heap_base = ioremap(*(u64 *)(config + TXTCR_HEAP_BASE), + *(u64 *)(config + TXTCR_HEAP_SIZE)); + iounmap(config); + if (!heap_base) + return NULL; + + /* walk heap to SinitMleData */ + /* skip BiosData */ + heap_ptr = heap_base + *(u64 *)heap_base; + /* skip OsMleData */ + heap_ptr += *(u64 *)heap_ptr; + /* skip OsSinitData */ + heap_ptr += *(u64 *)heap_ptr; + /* now points to SinitMleDataSize; set to SinitMleData */ + heap_ptr += sizeof(u64); + /* get addr of DMAR table */ + dmar_tbl = (struct acpi_table_header *)(heap_ptr + + ((struct sinit_mle_data *)heap_ptr)->vtd_dmars_off - + sizeof(u64)); + + /* don't unmap heap because dmar.c needs access to this */ + + return dmar_tbl; +} + +int tboot_force_iommu(void) +{ + if (!tboot_enabled()) + return 0; + + if (no_iommu || swiotlb || dmar_disabled) + pr_warning("Forcing Intel-IOMMU to enabled\n"); + + dmar_disabled = 0; +#ifdef CONFIG_SWIOTLB + swiotlb = 0; +#endif + no_iommu = 0; + + return 1; +} diff --git a/security/Kconfig b/security/Kconfig index d23c839038f..edc7cbdc012 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -113,6 +113,36 @@ config SECURITY_ROOTPLUG If you are unsure how to answer this question, answer N. +config INTEL_TXT + bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)" + depends on EXPERIMENTAL && X86 && DMAR && ACPI + help + This option enables support for booting the kernel with the + Trusted Boot (tboot) module. This will utilize + Intel(R) Trusted Execution Technology to perform a measured launch + of the kernel. If the system does not support Intel(R) TXT, this + will have no effect. + + Intel TXT will provide higher assurance of sysem configuration and + initial state as well as data reset protection. This is used to + create a robust initial kernel measurement and verification, which + helps to ensure that kernel security mechanisms are functioning + correctly. This level of protection requires a root of trust outside + of the kernel itself. + + Intel TXT also helps solve real end user concerns about having + confidence that their hardware is running the VMM or kernel that + it was conigured with, especially since they may be responsible for + providing such assurances to VMs and services running on it. + + See for more information + about Intel(R) TXT. + See for more information about tboot. + See Documentation/intel_txt.txt for a description of how to enable + Intel TXT support in a kernel boot. + + If you are unsure as to whether this is required, answer N. + source security/selinux/Kconfig source security/smack/Kconfig source security/tomoyo/Kconfig -- cgit v1.2.3-70-g09d2 From b5d6f93b92a37466b43ba105f524bdf046d3bb3c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 23 Jul 2009 12:25:40 +0200 Subject: ALSA: hda - Add description of new models for ALC889/889A Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index a1895d7f3cf..4c95a6c3f79 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -155,6 +155,8 @@ ALC882/883/885/888/889 fujitsu-pi2515 Fujitsu AMILO Pi2515 fujitsu-xa3530 Fujitsu AMILO XA3530 3stack-6ch-intel Intel DG33* boards + intel-alc889a Intel IbexPeak with ALC889A + intel-x58 Intel DX58 with ALC889 asus-p5q ASUS P5Q-EM boards mb31 MacBook 3,1 sony-vaio-tt Sony VAIO TT -- cgit v1.2.3-70-g09d2 From 987b8816661332978efd0f85bedf9866fe2e3232 Mon Sep 17 00:00:00 2001 From: Thadeu Lima de Souza Cascardo Date: Sun, 26 Jul 2009 12:34:40 -0300 Subject: trivial: fix typo in ieee802154 documentation and add it to index Signed-off-by: Thadeu Lima de Souza Cascardo --- Documentation/networking/00-INDEX | 2 ++ Documentation/networking/ieee802154.txt | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX index 1634c6dceca..50189bf07d5 100644 --- a/Documentation/networking/00-INDEX +++ b/Documentation/networking/00-INDEX @@ -60,6 +60,8 @@ framerelay.txt - info on using Frame Relay/Data Link Connection Identifier (DLCI). generic_netlink.txt - info on Generic Netlink +ieee802154.txt + - Linux IEEE 802.15.4 implementation, API and drivers ip-sysctl.txt - /proc/sys/net/ipv4/* variables ip_dynaddr.txt diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt index a0280ad2edc..1d4ed66b1b1 100644 --- a/Documentation/networking/ieee802154.txt +++ b/Documentation/networking/ieee802154.txt @@ -69,7 +69,7 @@ We provide an example of simple HardMAC driver at drivers/ieee802154/fakehard.c SoftMAC ======= -We are going to provide intermediate layer impelementing IEEE 802.15.4 MAC +We are going to provide intermediate layer implementing IEEE 802.15.4 MAC in software. This is currently WIP. See header include/net/ieee802154/mac802154.h and several drivers in -- cgit v1.2.3-70-g09d2 From 9a11f1aa8e14798037d0c9ac134696fa3af6eb2a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Jul 2009 16:01:20 +0200 Subject: ALSA: hda - Reword information messages for BIOS auto-probing mode The sentense "Unknown model for xxx, ..." makes people too nervous and drives them to a direction to a wrong "fix" by giving any mismatching model option. Let's rephrase the messages to be more nice and easy (at least that won't make people suspect conspiracies). Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio.txt | 4 ++++ sound/pci/hda/patch_analog.c | 3 ++- sound/pci/hda/patch_cmedia.c | 3 ++- sound/pci/hda/patch_realtek.c | 34 ++++++++++++++++------------------ sound/pci/hda/patch_sigmatel.c | 34 ++++++++++++++++++---------------- 5 files changed, 42 insertions(+), 36 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio.txt b/Documentation/sound/alsa/HD-Audio.txt index 0b5b480708f..7b8a5f947d1 100644 --- a/Documentation/sound/alsa/HD-Audio.txt +++ b/Documentation/sound/alsa/HD-Audio.txt @@ -138,6 +138,10 @@ override the BIOS setup or to provide more comprehensive features. The driver checks PCI SSID and looks through the static configuration table until any matching entry is found. If you have a new machine, you may see a message like below: +------------------------------------------------------------------------ + hda_codec: ALC880: BIOS auto-probing. +------------------------------------------------------------------------ +Meanwhile, in the earlier versions, you would see a message like: ------------------------------------------------------------------------ hda_codec: Unknown model for ALC880, trying auto-probe from BIOS... ------------------------------------------------------------------------ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 3da85caf8af..ab3bcb78ace 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -2982,7 +2982,8 @@ static int patch_ad1988(struct hda_codec *codec) board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, ad1988_models, ad1988_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n"); + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); board_config = AD1988_AUTO; } diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index c921264bbd7..780e1a72114 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -635,7 +635,8 @@ static int patch_cmi9880(struct hda_codec *codec) cmi9880_models, cmi9880_cfg_tbl); if (spec->board_config < 0) { - snd_printdd(KERN_INFO "hda_codec: Unknown model for CMI9880\n"); + snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); spec->board_config = CMI_AUTO; /* try everything */ } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index df87c01e27d..6794d028119 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4584,8 +4584,8 @@ static int patch_alc880(struct hda_codec *codec) alc880_models, alc880_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); board_config = ALC880_AUTO; } @@ -6228,8 +6228,7 @@ static int patch_alc260(struct hda_codec *codec) alc260_models, alc260_cfg_tbl); if (board_config < 0) { - snd_printd(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", + snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", codec->chip_name); board_config = ALC260_AUTO; } @@ -9526,8 +9525,7 @@ static int patch_alc882(struct hda_codec *codec) ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl); if (board_config < 0 || board_config >= ALC882_MODEL_LAST) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", codec->chip_name); board_config = ALC882_AUTO; } @@ -11406,8 +11404,8 @@ static int patch_alc262(struct hda_codec *codec) alc262_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); board_config = ALC262_AUTO; } @@ -12479,8 +12477,8 @@ static int patch_alc268(struct hda_codec *codec) alc268_cfg_tbl); if (board_config < 0 || board_config >= ALC268_MODEL_LAST) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); board_config = ALC268_AUTO; } @@ -13297,8 +13295,8 @@ static int patch_alc269(struct hda_codec *codec) alc269_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); board_config = ALC269_AUTO; } @@ -14448,8 +14446,8 @@ static int patch_alc861(struct hda_codec *codec) alc861_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); board_config = ALC861_AUTO; } @@ -15372,8 +15370,8 @@ static int patch_alc861vd(struct hda_codec *codec) alc861vd_cfg_tbl); if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); board_config = ALC861VD_AUTO; } @@ -17296,8 +17294,8 @@ static int patch_alc662(struct hda_codec *codec) alc662_models, alc662_cfg_tbl); if (board_config < 0) { - printk(KERN_INFO "hda_codec: Unknown model for %s, " - "trying auto-probe from BIOS...\n", codec->chip_name); + printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); board_config = ALC662_AUTO; } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 9de97f30699..c6dc625c66b 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4794,7 +4794,8 @@ static int patch_stac9200(struct hda_codec *codec) stac9200_models, stac9200_cfg_tbl); if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9200, using BIOS defaults\n"); + snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); else stac92xx_set_config_regs(codec, stac9200_brd_tbl[spec->board_config]); @@ -4866,8 +4867,8 @@ static int patch_stac925x(struct hda_codec *codec) stac925x_cfg_tbl); again: if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC925x," - "using BIOS defaults\n"); + snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); else stac92xx_set_config_regs(codec, stac925x_brd_tbl[spec->board_config]); @@ -4949,8 +4950,8 @@ static int patch_stac92hd73xx(struct hda_codec *codec) stac92hd73xx_cfg_tbl); again: if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: Unknown model for" - " STAC92HD73XX, using BIOS defaults\n"); + snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); else stac92xx_set_config_regs(codec, stac92hd73xx_brd_tbl[spec->board_config]); @@ -5125,8 +5126,8 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) stac92hd83xxx_cfg_tbl); again: if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: Unknown model for" - " STAC92HD83XXX, using BIOS defaults\n"); + snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); else stac92xx_set_config_regs(codec, stac92hd83xxx_brd_tbl[spec->board_config]); @@ -5291,8 +5292,8 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) stac92hd71bxx_cfg_tbl); again: if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: Unknown model for" - " STAC92HD71BXX, using BIOS defaults\n"); + snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); else stac92xx_set_config_regs(codec, stac92hd71bxx_brd_tbl[spec->board_config]); @@ -5547,8 +5548,8 @@ static int patch_stac922x(struct hda_codec *codec) again: if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC922x, " - "using BIOS defaults\n"); + snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); else stac92xx_set_config_regs(codec, stac922x_brd_tbl[spec->board_config]); @@ -5610,8 +5611,8 @@ static int patch_stac927x(struct hda_codec *codec) stac927x_cfg_tbl); again: if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: Unknown model for" - "STAC927x, using BIOS defaults\n"); + snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); else stac92xx_set_config_regs(codec, stac927x_brd_tbl[spec->board_config]); @@ -5738,7 +5739,8 @@ static int patch_stac9205(struct hda_codec *codec) stac9205_cfg_tbl); again: if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9205, using BIOS defaults\n"); + snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); else stac92xx_set_config_regs(codec, stac9205_brd_tbl[spec->board_config]); @@ -5890,8 +5892,8 @@ static int patch_stac9872(struct hda_codec *codec) stac9872_models, stac9872_cfg_tbl); if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: Unknown model for STAC9872, " - "using BIOS defaults\n"); + snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec->chip_name); else stac92xx_set_config_regs(codec, stac9872_brd_tbl[spec->board_config]); -- cgit v1.2.3-70-g09d2 From dfff4e95d749c414af3f7350835139103408a50d Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Thu, 30 Jul 2009 23:23:41 +0100 Subject: ARM: S3C: CPUFREQ: Add documentation for system Add documentation for the S3C24XX style CPUFREQ driver. Signed-off-by: Ben Dooks Signed-off-by: Ben Dooks --- Documentation/arm/Samsung-S3C24XX/CPUfreq.txt | 75 +++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 Documentation/arm/Samsung-S3C24XX/CPUfreq.txt (limited to 'Documentation') diff --git a/Documentation/arm/Samsung-S3C24XX/CPUfreq.txt b/Documentation/arm/Samsung-S3C24XX/CPUfreq.txt new file mode 100644 index 00000000000..76b3a11e90b --- /dev/null +++ b/Documentation/arm/Samsung-S3C24XX/CPUfreq.txt @@ -0,0 +1,75 @@ + S3C24XX CPUfreq support + ======================= + +Introduction +------------ + + The S3C24XX series support a number of power saving systems, such as + the ability to change the core, memory and peripheral operating + frequencies. The core control is exported via the CPUFreq driver + which has a number of different manual or automatic controls over the + rate the core is running at. + + There are two forms of the driver depending on the specific CPU and + how the clocks are arranged. The first implementation used as single + PLL to feed the ARM, memory and peripherals via a series of dividers + and muxes and this is the implementation that is documented here. A + newer version where there is a seperate PLL and clock divider for the + ARM core is available as a seperate driver. + + +Layout +------ + + The code core manages the CPU specific drivers, any data that they + need to register and the interface to the generic drivers/cpufreq + system. Each CPU registers a driver to control the PLL, clock dividers + and anything else associated with it. Any board that wants to use this + framework needs to supply at least basic details of what is required. + + The core registers with drivers/cpufreq at init time if all the data + necessary has been supplied. + + +CPU support +----------- + + The support for each CPU depends on the facilities provided by the + SoC and the driver as each device has different PLL and clock chains + associated with it. + + +Slow Mode +--------- + + The SLOW mode where the PLL is turned off altogether and the + system is fed by the external crystal input is currently not + supported. + + +sysfs +----- + + The core code exports extra information via sysfs in the directory + devices/system/cpu/cpu0/arch-freq. + + +Board Support +------------- + + Each board that wants to use the cpufreq code must register some basic + information with the core driver to provide information about what the + board requires and any restrictions being placed on it. + + The board needs to supply information about whether it needs the IO bank + timings changing, any maximum frequency limits and information about the + SDRAM refresh rate. + + + + +Document Author +--------------- + +Ben Dooks, Copyright 2009 Simtec Electronics +Licensed under GPLv2 -- cgit v1.2.3-70-g09d2 From cbf1107126af2950623fafdaa5c9df43ab00f046 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 9 Aug 2009 15:06:19 -0400 Subject: SUNRPC: convert some sysctls into module parameters Parameters like the minimum reserved port, and the number of slot entries should really be module parameters rather than sysctls. Signed-off-by: Trond Myklebust --- Documentation/kernel-parameters.txt | 21 +++++++++++++++ net/sunrpc/xprtsock.c | 52 +++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index dd1a6d4bb74..2f1820683b6 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2391,6 +2391,18 @@ and is between 256 and 4096 characters. It is defined in the file stifb= [HW] Format: bpp:[:[:...]] + sunrpc.min_resvport= + sunrpc.max_resvport= + [NFS,SUNRPC] + SunRPC servers often require that client requests + originate from a privileged port (i.e. a port in the + range 0 < portnr < 1024). + An administrator who wishes to reserve some of these + ports for other uses may adjust the range that the + kernel's sunrpc client considers to be privileged + using these two parameters to set the minimum and + maximum port values. + sunrpc.pool_mode= [NFS] Control how the NFS server code allocates CPUs to @@ -2407,6 +2419,15 @@ and is between 256 and 4096 characters. It is defined in the file pernode one pool for each NUMA node (equivalent to global on non-NUMA machines) + sunrpc.tcp_slot_table_entries= + sunrpc.udp_slot_table_entries= + [NFS,SUNRPC] + Sets the upper limit on the number of simultaneous + RPC calls that can be sent from the client to a + server. Increasing these values may allow you to + improve throughput, but will also increase the + amount of memory reserved for use by the client. + swiotlb= [IA-64] Number of I/O TLB slabs switches= [HW,M68k] diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 83c73c4d017..585a864c1c4 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2412,3 +2412,55 @@ void cleanup_socket_xprt(void) xprt_unregister_transport(&xs_udp_transport); xprt_unregister_transport(&xs_tcp_transport); } + +static int param_set_uint_minmax(const char *val, struct kernel_param *kp, + unsigned int min, unsigned int max) +{ + unsigned long num; + int ret; + + if (!val) + return -EINVAL; + ret = strict_strtoul(val, 0, &num); + if (ret == -EINVAL || num < min || num > max) + return -EINVAL; + *((unsigned int *)kp->arg) = num; + return 0; +} + +static int param_set_portnr(const char *val, struct kernel_param *kp) +{ + return param_set_uint_minmax(val, kp, + RPC_MIN_RESVPORT, + RPC_MAX_RESVPORT); +} + +static int param_get_portnr(char *buffer, struct kernel_param *kp) +{ + return param_get_uint(buffer, kp); +} +#define param_check_portnr(name, p) \ + __param_check(name, p, unsigned int); + +module_param_named(min_resvport, xprt_min_resvport, portnr, 0644); +module_param_named(max_resvport, xprt_max_resvport, portnr, 0644); + +static int param_set_slot_table_size(const char *val, struct kernel_param *kp) +{ + return param_set_uint_minmax(val, kp, + RPC_MIN_SLOT_TABLE, + RPC_MAX_SLOT_TABLE); +} + +static int param_get_slot_table_size(char *buffer, struct kernel_param *kp) +{ + return param_get_uint(buffer, kp); +} +#define param_check_slot_table_size(name, p) \ + __param_check(name, p, unsigned int); + +module_param_named(tcp_slot_table_entries, xprt_tcp_slot_table_entries, + slot_table_size, 0644); +module_param_named(udp_slot_table_entries, xprt_udp_slot_table_entries, + slot_table_size, 0644); + -- cgit v1.2.3-70-g09d2 From 7cd1837b5d24417eca667d674a97bea936849785 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 12 Jun 2009 18:36:33 +0200 Subject: netfilter: xtables: remove xt_TOS v0 Superseded by xt_TOS v1 (v2.6.24-2396-g5c350e5). Signed-off-by: Jan Engelhardt --- Documentation/feature-removal-schedule.txt | 3 -- include/linux/netfilter_ipv4/Kbuild | 2 -- include/linux/netfilter_ipv4/ipt_TOS.h | 12 -------- include/linux/netfilter_ipv4/ipt_tos.h | 13 --------- net/netfilter/xt_DSCP.c | 46 ------------------------------ net/netfilter/xt_dscp.c | 17 ----------- 6 files changed, 93 deletions(-) delete mode 100644 include/linux/netfilter_ipv4/ipt_TOS.h delete mode 100644 include/linux/netfilter_ipv4/ipt_tos.h (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index f8cd450be9a..3aa4a779092 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -235,9 +235,6 @@ Who: Thomas Gleixner --------------------------- What (Why): - - include/linux/netfilter_ipv4/ipt_TOS.h ipt_tos.h header files - (superseded by xt_TOS/xt_tos target & match) - - "forwarding" header files like ipt_mac.h in include/linux/netfilter_ipv4/ and include/linux/netfilter_ipv6/ diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild index 3a7105bb8f3..86d81a285f9 100644 --- a/include/linux/netfilter_ipv4/Kbuild +++ b/include/linux/netfilter_ipv4/Kbuild @@ -9,7 +9,6 @@ header-y += ipt_NFQUEUE.h header-y += ipt_REJECT.h header-y += ipt_SAME.h header-y += ipt_TCPMSS.h -header-y += ipt_TOS.h header-y += ipt_TTL.h header-y += ipt_ULOG.h header-y += ipt_addrtype.h @@ -40,7 +39,6 @@ header-y += ipt_sctp.h header-y += ipt_state.h header-y += ipt_string.h header-y += ipt_tcpmss.h -header-y += ipt_tos.h header-y += ipt_ttl.h unifdef-y += ip_queue.h diff --git a/include/linux/netfilter_ipv4/ipt_TOS.h b/include/linux/netfilter_ipv4/ipt_TOS.h deleted file mode 100644 index 6bf9e1fdfd8..00000000000 --- a/include/linux/netfilter_ipv4/ipt_TOS.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _IPT_TOS_H_target -#define _IPT_TOS_H_target - -#ifndef IPTOS_NORMALSVC -#define IPTOS_NORMALSVC 0 -#endif - -struct ipt_tos_target_info { - u_int8_t tos; -}; - -#endif /*_IPT_TOS_H_target*/ diff --git a/include/linux/netfilter_ipv4/ipt_tos.h b/include/linux/netfilter_ipv4/ipt_tos.h deleted file mode 100644 index a21f5df23c5..00000000000 --- a/include/linux/netfilter_ipv4/ipt_tos.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _IPT_TOS_H -#define _IPT_TOS_H - -struct ipt_tos_info { - u_int8_t tos; - u_int8_t invert; -}; - -#ifndef IPTOS_NORMALSVC -#define IPTOS_NORMALSVC 0 -#endif - -#endif /*_IPT_TOS_H*/ diff --git a/net/netfilter/xt_DSCP.c b/net/netfilter/xt_DSCP.c index 6a347e768f8..74ce8926005 100644 --- a/net/netfilter/xt_DSCP.c +++ b/net/netfilter/xt_DSCP.c @@ -18,7 +18,6 @@ #include #include -#include MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("Xtables: DSCP/TOS field modification"); @@ -72,41 +71,6 @@ static bool dscp_tg_check(const struct xt_tgchk_param *par) return true; } -static unsigned int -tos_tg_v0(struct sk_buff *skb, const struct xt_target_param *par) -{ - const struct ipt_tos_target_info *info = par->targinfo; - struct iphdr *iph = ip_hdr(skb); - u_int8_t oldtos; - - if ((iph->tos & IPTOS_TOS_MASK) != info->tos) { - if (!skb_make_writable(skb, sizeof(struct iphdr))) - return NF_DROP; - - iph = ip_hdr(skb); - oldtos = iph->tos; - iph->tos = (iph->tos & IPTOS_PREC_MASK) | info->tos; - csum_replace2(&iph->check, htons(oldtos), htons(iph->tos)); - } - - return XT_CONTINUE; -} - -static bool tos_tg_check_v0(const struct xt_tgchk_param *par) -{ - const struct ipt_tos_target_info *info = par->targinfo; - const uint8_t tos = info->tos; - - if (tos != IPTOS_LOWDELAY && tos != IPTOS_THROUGHPUT && - tos != IPTOS_RELIABILITY && tos != IPTOS_MINCOST && - tos != IPTOS_NORMALSVC) { - printk(KERN_WARNING "TOS: bad tos value %#x\n", tos); - return false; - } - - return true; -} - static unsigned int tos_tg(struct sk_buff *skb, const struct xt_target_param *par) { @@ -166,16 +130,6 @@ static struct xt_target dscp_tg_reg[] __read_mostly = { .table = "mangle", .me = THIS_MODULE, }, - { - .name = "TOS", - .revision = 0, - .family = NFPROTO_IPV4, - .table = "mangle", - .target = tos_tg_v0, - .targetsize = sizeof(struct ipt_tos_target_info), - .checkentry = tos_tg_check_v0, - .me = THIS_MODULE, - }, { .name = "TOS", .revision = 1, diff --git a/net/netfilter/xt_dscp.c b/net/netfilter/xt_dscp.c index c3f8085460d..0280d3a8c16 100644 --- a/net/netfilter/xt_dscp.c +++ b/net/netfilter/xt_dscp.c @@ -15,7 +15,6 @@ #include #include -#include MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("Xtables: DSCP/TOS field match"); @@ -55,14 +54,6 @@ static bool dscp_mt_check(const struct xt_mtchk_param *par) return true; } -static bool -tos_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) -{ - const struct ipt_tos_info *info = par->matchinfo; - - return (ip_hdr(skb)->tos == info->tos) ^ info->invert; -} - static bool tos_mt(const struct sk_buff *skb, const struct xt_match_param *par) { const struct xt_tos_match_info *info = par->matchinfo; @@ -92,14 +83,6 @@ static struct xt_match dscp_mt_reg[] __read_mostly = { .matchsize = sizeof(struct xt_dscp_info), .me = THIS_MODULE, }, - { - .name = "tos", - .revision = 0, - .family = NFPROTO_IPV4, - .match = tos_mt_v0, - .matchsize = sizeof(struct ipt_tos_info), - .me = THIS_MODULE, - }, { .name = "tos", .revision = 1, -- cgit v1.2.3-70-g09d2 From e973a70ca033bfcd4d8b59d1f66bfc1e782e1276 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 12 Jun 2009 18:42:12 +0200 Subject: netfilter: xtables: remove xt_CONNMARK v0 Superseded by xt_CONNMARK v1 (v2.6.24-2917-g0dc8c76). Signed-off-by: Jan Engelhardt --- Documentation/feature-removal-schedule.txt | 3 - include/linux/netfilter/xt_CONNMARK.h | 6 -- net/netfilter/xt_CONNMARK.c | 134 +++-------------------------- 3 files changed, 11 insertions(+), 132 deletions(-) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 3aa4a779092..7eccf945d4e 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -238,9 +238,6 @@ What (Why): - "forwarding" header files like ipt_mac.h in include/linux/netfilter_ipv4/ and include/linux/netfilter_ipv6/ - - xt_CONNMARK match revision 0 - (superseded by xt_CONNMARK match revision 1) - - xt_MARK target revisions 0 and 1 (superseded by xt_MARK match revision 2) diff --git a/include/linux/netfilter/xt_CONNMARK.h b/include/linux/netfilter/xt_CONNMARK.h index 7635c8ffdad..0a854586675 100644 --- a/include/linux/netfilter/xt_CONNMARK.h +++ b/include/linux/netfilter/xt_CONNMARK.h @@ -18,12 +18,6 @@ enum { XT_CONNMARK_RESTORE }; -struct xt_connmark_target_info { - unsigned long mark; - unsigned long mask; - __u8 mode; -}; - struct xt_connmark_tginfo1 { __u32 ctmark, ctmask, nfmask; __u8 mode; diff --git a/net/netfilter/xt_CONNMARK.c b/net/netfilter/xt_CONNMARK.c index d6e5ab46327..593457068ae 100644 --- a/net/netfilter/xt_CONNMARK.c +++ b/net/netfilter/xt_CONNMARK.c @@ -35,45 +35,6 @@ MODULE_ALIAS("ip6t_CONNMARK"); #include #include -static unsigned int -connmark_tg_v0(struct sk_buff *skb, const struct xt_target_param *par) -{ - const struct xt_connmark_target_info *markinfo = par->targinfo; - struct nf_conn *ct; - enum ip_conntrack_info ctinfo; - u_int32_t diff; - u_int32_t mark; - u_int32_t newmark; - - ct = nf_ct_get(skb, &ctinfo); - if (ct) { - switch(markinfo->mode) { - case XT_CONNMARK_SET: - newmark = (ct->mark & ~markinfo->mask) | markinfo->mark; - if (newmark != ct->mark) { - ct->mark = newmark; - nf_conntrack_event_cache(IPCT_MARK, ct); - } - break; - case XT_CONNMARK_SAVE: - newmark = (ct->mark & ~markinfo->mask) | - (skb->mark & markinfo->mask); - if (ct->mark != newmark) { - ct->mark = newmark; - nf_conntrack_event_cache(IPCT_MARK, ct); - } - break; - case XT_CONNMARK_RESTORE: - mark = skb->mark; - diff = (ct->mark ^ mark) & markinfo->mask; - skb->mark = mark ^ diff; - break; - } - } - - return XT_CONTINUE; -} - static unsigned int connmark_tg(struct sk_buff *skb, const struct xt_target_param *par) { @@ -112,30 +73,6 @@ connmark_tg(struct sk_buff *skb, const struct xt_target_param *par) return XT_CONTINUE; } -static bool connmark_tg_check_v0(const struct xt_tgchk_param *par) -{ - const struct xt_connmark_target_info *matchinfo = par->targinfo; - - if (matchinfo->mode == XT_CONNMARK_RESTORE) { - if (strcmp(par->table, "mangle") != 0) { - printk(KERN_WARNING "CONNMARK: restore can only be " - "called from \"mangle\" table, not \"%s\"\n", - par->table); - return false; - } - } - if (matchinfo->mark > 0xffffffff || matchinfo->mask > 0xffffffff) { - printk(KERN_WARNING "CONNMARK: Only supports 32bit mark\n"); - return false; - } - if (nf_ct_l3proto_try_module_get(par->family) < 0) { - printk(KERN_WARNING "can't load conntrack support for " - "proto=%u\n", par->family); - return false; - } - return true; -} - static bool connmark_tg_check(const struct xt_tgchk_param *par) { if (nf_ct_l3proto_try_module_get(par->family) < 0) { @@ -151,74 +88,25 @@ static void connmark_tg_destroy(const struct xt_tgdtor_param *par) nf_ct_l3proto_module_put(par->family); } -#ifdef CONFIG_COMPAT -struct compat_xt_connmark_target_info { - compat_ulong_t mark, mask; - u_int8_t mode; - u_int8_t __pad1; - u_int16_t __pad2; -}; - -static void connmark_tg_compat_from_user_v0(void *dst, void *src) -{ - const struct compat_xt_connmark_target_info *cm = src; - struct xt_connmark_target_info m = { - .mark = cm->mark, - .mask = cm->mask, - .mode = cm->mode, - }; - memcpy(dst, &m, sizeof(m)); -} - -static int connmark_tg_compat_to_user_v0(void __user *dst, void *src) -{ - const struct xt_connmark_target_info *m = src; - struct compat_xt_connmark_target_info cm = { - .mark = m->mark, - .mask = m->mask, - .mode = m->mode, - }; - return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; -} -#endif /* CONFIG_COMPAT */ - -static struct xt_target connmark_tg_reg[] __read_mostly = { - { - .name = "CONNMARK", - .revision = 0, - .family = NFPROTO_UNSPEC, - .checkentry = connmark_tg_check_v0, - .destroy = connmark_tg_destroy, - .target = connmark_tg_v0, - .targetsize = sizeof(struct xt_connmark_target_info), -#ifdef CONFIG_COMPAT - .compatsize = sizeof(struct compat_xt_connmark_target_info), - .compat_from_user = connmark_tg_compat_from_user_v0, - .compat_to_user = connmark_tg_compat_to_user_v0, -#endif - .me = THIS_MODULE - }, - { - .name = "CONNMARK", - .revision = 1, - .family = NFPROTO_UNSPEC, - .checkentry = connmark_tg_check, - .target = connmark_tg, - .targetsize = sizeof(struct xt_connmark_tginfo1), - .destroy = connmark_tg_destroy, - .me = THIS_MODULE, - }, +static struct xt_target connmark_tg_reg __read_mostly = { + .name = "CONNMARK", + .revision = 1, + .family = NFPROTO_UNSPEC, + .checkentry = connmark_tg_check, + .target = connmark_tg, + .targetsize = sizeof(struct xt_connmark_tginfo1), + .destroy = connmark_tg_destroy, + .me = THIS_MODULE, }; static int __init connmark_tg_init(void) { - return xt_register_targets(connmark_tg_reg, - ARRAY_SIZE(connmark_tg_reg)); + return xt_register_target(&connmark_tg_reg); } static void __exit connmark_tg_exit(void) { - xt_unregister_targets(connmark_tg_reg, ARRAY_SIZE(connmark_tg_reg)); + xt_unregister_target(&connmark_tg_reg); } module_init(connmark_tg_init); -- cgit v1.2.3-70-g09d2 From c8001f7fd5a4684280fddceed9fae9ea2e4fb521 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 12 Jun 2009 18:47:32 +0200 Subject: netfilter: xtables: remove xt_MARK v0, v1 Superseded by xt_MARK v2 (v2.6.24-2918-ge0a812a). Signed-off-by: Jan Engelhardt --- Documentation/feature-removal-schedule.txt | 3 - include/linux/netfilter/xt_MARK.h | 17 --- net/netfilter/xt_MARK.c | 163 ++--------------------------- 3 files changed, 9 insertions(+), 174 deletions(-) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 7eccf945d4e..121e19c9eee 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -238,9 +238,6 @@ What (Why): - "forwarding" header files like ipt_mac.h in include/linux/netfilter_ipv4/ and include/linux/netfilter_ipv6/ - - xt_MARK target revisions 0 and 1 - (superseded by xt_MARK match revision 2) - - xt_connmark match revision 0 (superseded by xt_connmark match revision 1) diff --git a/include/linux/netfilter/xt_MARK.h b/include/linux/netfilter/xt_MARK.h index 028304bcc0b..bc9561bdef7 100644 --- a/include/linux/netfilter/xt_MARK.h +++ b/include/linux/netfilter/xt_MARK.h @@ -3,23 +3,6 @@ #include -/* Version 0 */ -struct xt_mark_target_info { - unsigned long mark; -}; - -/* Version 1 */ -enum { - XT_MARK_SET=0, - XT_MARK_AND, - XT_MARK_OR, -}; - -struct xt_mark_target_info_v1 { - unsigned long mark; - __u8 mode; -}; - struct xt_mark_tginfo2 { __u32 mark, mask; }; diff --git a/net/netfilter/xt_MARK.c b/net/netfilter/xt_MARK.c index 67574bcfb8a..225f8d11e17 100644 --- a/net/netfilter/xt_MARK.c +++ b/net/netfilter/xt_MARK.c @@ -24,39 +24,6 @@ MODULE_DESCRIPTION("Xtables: packet mark modification"); MODULE_ALIAS("ipt_MARK"); MODULE_ALIAS("ip6t_MARK"); -static unsigned int -mark_tg_v0(struct sk_buff *skb, const struct xt_target_param *par) -{ - const struct xt_mark_target_info *markinfo = par->targinfo; - - skb->mark = markinfo->mark; - return XT_CONTINUE; -} - -static unsigned int -mark_tg_v1(struct sk_buff *skb, const struct xt_target_param *par) -{ - const struct xt_mark_target_info_v1 *markinfo = par->targinfo; - int mark = 0; - - switch (markinfo->mode) { - case XT_MARK_SET: - mark = markinfo->mark; - break; - - case XT_MARK_AND: - mark = skb->mark & markinfo->mark; - break; - - case XT_MARK_OR: - mark = skb->mark | markinfo->mark; - break; - } - - skb->mark = mark; - return XT_CONTINUE; -} - static unsigned int mark_tg(struct sk_buff *skb, const struct xt_target_param *par) { @@ -66,135 +33,23 @@ mark_tg(struct sk_buff *skb, const struct xt_target_param *par) return XT_CONTINUE; } -static bool mark_tg_check_v0(const struct xt_tgchk_param *par) -{ - const struct xt_mark_target_info *markinfo = par->targinfo; - - if (markinfo->mark > 0xffffffff) { - printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n"); - return false; - } - return true; -} - -static bool mark_tg_check_v1(const struct xt_tgchk_param *par) -{ - const struct xt_mark_target_info_v1 *markinfo = par->targinfo; - - if (markinfo->mode != XT_MARK_SET - && markinfo->mode != XT_MARK_AND - && markinfo->mode != XT_MARK_OR) { - printk(KERN_WARNING "MARK: unknown mode %u\n", - markinfo->mode); - return false; - } - if (markinfo->mark > 0xffffffff) { - printk(KERN_WARNING "MARK: Only supports 32bit wide mark\n"); - return false; - } - return true; -} - -#ifdef CONFIG_COMPAT -struct compat_xt_mark_target_info { - compat_ulong_t mark; -}; - -static void mark_tg_compat_from_user_v0(void *dst, void *src) -{ - const struct compat_xt_mark_target_info *cm = src; - struct xt_mark_target_info m = { - .mark = cm->mark, - }; - memcpy(dst, &m, sizeof(m)); -} - -static int mark_tg_compat_to_user_v0(void __user *dst, void *src) -{ - const struct xt_mark_target_info *m = src; - struct compat_xt_mark_target_info cm = { - .mark = m->mark, - }; - return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; -} - -struct compat_xt_mark_target_info_v1 { - compat_ulong_t mark; - u_int8_t mode; - u_int8_t __pad1; - u_int16_t __pad2; -}; - -static void mark_tg_compat_from_user_v1(void *dst, void *src) -{ - const struct compat_xt_mark_target_info_v1 *cm = src; - struct xt_mark_target_info_v1 m = { - .mark = cm->mark, - .mode = cm->mode, - }; - memcpy(dst, &m, sizeof(m)); -} - -static int mark_tg_compat_to_user_v1(void __user *dst, void *src) -{ - const struct xt_mark_target_info_v1 *m = src; - struct compat_xt_mark_target_info_v1 cm = { - .mark = m->mark, - .mode = m->mode, - }; - return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; -} -#endif /* CONFIG_COMPAT */ - -static struct xt_target mark_tg_reg[] __read_mostly = { - { - .name = "MARK", - .family = NFPROTO_UNSPEC, - .revision = 0, - .checkentry = mark_tg_check_v0, - .target = mark_tg_v0, - .targetsize = sizeof(struct xt_mark_target_info), -#ifdef CONFIG_COMPAT - .compatsize = sizeof(struct compat_xt_mark_target_info), - .compat_from_user = mark_tg_compat_from_user_v0, - .compat_to_user = mark_tg_compat_to_user_v0, -#endif - .table = "mangle", - .me = THIS_MODULE, - }, - { - .name = "MARK", - .family = NFPROTO_UNSPEC, - .revision = 1, - .checkentry = mark_tg_check_v1, - .target = mark_tg_v1, - .targetsize = sizeof(struct xt_mark_target_info_v1), -#ifdef CONFIG_COMPAT - .compatsize = sizeof(struct compat_xt_mark_target_info_v1), - .compat_from_user = mark_tg_compat_from_user_v1, - .compat_to_user = mark_tg_compat_to_user_v1, -#endif - .table = "mangle", - .me = THIS_MODULE, - }, - { - .name = "MARK", - .revision = 2, - .family = NFPROTO_UNSPEC, - .target = mark_tg, - .targetsize = sizeof(struct xt_mark_tginfo2), - .me = THIS_MODULE, - }, +static struct xt_target mark_tg_reg __read_mostly = { + .name = "MARK", + .revision = 2, + .family = NFPROTO_UNSPEC, + .target = mark_tg, + .targetsize = sizeof(struct xt_mark_tginfo2), + .me = THIS_MODULE, }; static int __init mark_tg_init(void) { - return xt_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg)); + return xt_register_target(&mark_tg_reg); } static void __exit mark_tg_exit(void) { - xt_unregister_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg)); + xt_unregister_target(&mark_tg_reg); } module_init(mark_tg_init); -- cgit v1.2.3-70-g09d2 From 84899a2b9adaf6c2e20d198d7c24562ce6b391d8 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 12 Jun 2009 18:50:33 +0200 Subject: netfilter: xtables: remove xt_connmark v0 Superseded by xt_connmark v1 (v2.6.24-2919-g96e3227). Signed-off-by: Jan Engelhardt --- Documentation/feature-removal-schedule.txt | 3 - include/linux/netfilter/xt_connmark.h | 5 -- net/netfilter/xt_connmark.c | 101 ++++------------------------- 3 files changed, 11 insertions(+), 98 deletions(-) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 121e19c9eee..54f93579492 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -238,9 +238,6 @@ What (Why): - "forwarding" header files like ipt_mac.h in include/linux/netfilter_ipv4/ and include/linux/netfilter_ipv6/ - - xt_connmark match revision 0 - (superseded by xt_connmark match revision 1) - - xt_conntrack match revision 0 (superseded by xt_conntrack match revision 1) diff --git a/include/linux/netfilter/xt_connmark.h b/include/linux/netfilter/xt_connmark.h index 571e266d004..619e47cde01 100644 --- a/include/linux/netfilter/xt_connmark.h +++ b/include/linux/netfilter/xt_connmark.h @@ -12,11 +12,6 @@ * (at your option) any later version. */ -struct xt_connmark_info { - unsigned long mark, mask; - __u8 invert; -}; - struct xt_connmark_mtinfo1 { __u32 mark, mask; __u8 invert; diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c index 86cacab7a4a..122aa8b0147 100644 --- a/net/netfilter/xt_connmark.c +++ b/net/netfilter/xt_connmark.c @@ -47,36 +47,6 @@ connmark_mt(const struct sk_buff *skb, const struct xt_match_param *par) return ((ct->mark & info->mask) == info->mark) ^ info->invert; } -static bool -connmark_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) -{ - const struct xt_connmark_info *info = par->matchinfo; - const struct nf_conn *ct; - enum ip_conntrack_info ctinfo; - - ct = nf_ct_get(skb, &ctinfo); - if (!ct) - return false; - - return ((ct->mark & info->mask) == info->mark) ^ info->invert; -} - -static bool connmark_mt_check_v0(const struct xt_mtchk_param *par) -{ - const struct xt_connmark_info *cm = par->matchinfo; - - if (cm->mark > 0xffffffff || cm->mask > 0xffffffff) { - printk(KERN_WARNING "connmark: only support 32bit mark\n"); - return false; - } - if (nf_ct_l3proto_try_module_get(par->family) < 0) { - printk(KERN_WARNING "can't load conntrack support for " - "proto=%u\n", par->family); - return false; - } - return true; -} - static bool connmark_mt_check(const struct xt_mtchk_param *par) { if (nf_ct_l3proto_try_module_get(par->family) < 0) { @@ -92,74 +62,25 @@ static void connmark_mt_destroy(const struct xt_mtdtor_param *par) nf_ct_l3proto_module_put(par->family); } -#ifdef CONFIG_COMPAT -struct compat_xt_connmark_info { - compat_ulong_t mark, mask; - u_int8_t invert; - u_int8_t __pad1; - u_int16_t __pad2; -}; - -static void connmark_mt_compat_from_user_v0(void *dst, void *src) -{ - const struct compat_xt_connmark_info *cm = src; - struct xt_connmark_info m = { - .mark = cm->mark, - .mask = cm->mask, - .invert = cm->invert, - }; - memcpy(dst, &m, sizeof(m)); -} - -static int connmark_mt_compat_to_user_v0(void __user *dst, void *src) -{ - const struct xt_connmark_info *m = src; - struct compat_xt_connmark_info cm = { - .mark = m->mark, - .mask = m->mask, - .invert = m->invert, - }; - return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; -} -#endif /* CONFIG_COMPAT */ - -static struct xt_match connmark_mt_reg[] __read_mostly = { - { - .name = "connmark", - .revision = 0, - .family = NFPROTO_UNSPEC, - .checkentry = connmark_mt_check_v0, - .match = connmark_mt_v0, - .destroy = connmark_mt_destroy, - .matchsize = sizeof(struct xt_connmark_info), -#ifdef CONFIG_COMPAT - .compatsize = sizeof(struct compat_xt_connmark_info), - .compat_from_user = connmark_mt_compat_from_user_v0, - .compat_to_user = connmark_mt_compat_to_user_v0, -#endif - .me = THIS_MODULE - }, - { - .name = "connmark", - .revision = 1, - .family = NFPROTO_UNSPEC, - .checkentry = connmark_mt_check, - .match = connmark_mt, - .matchsize = sizeof(struct xt_connmark_mtinfo1), - .destroy = connmark_mt_destroy, - .me = THIS_MODULE, - }, +static struct xt_match connmark_mt_reg __read_mostly = { + .name = "connmark", + .revision = 1, + .family = NFPROTO_UNSPEC, + .checkentry = connmark_mt_check, + .match = connmark_mt, + .matchsize = sizeof(struct xt_connmark_mtinfo1), + .destroy = connmark_mt_destroy, + .me = THIS_MODULE, }; static int __init connmark_mt_init(void) { - return xt_register_matches(connmark_mt_reg, - ARRAY_SIZE(connmark_mt_reg)); + return xt_register_match(&connmark_mt_reg); } static void __exit connmark_mt_exit(void) { - xt_unregister_matches(connmark_mt_reg, ARRAY_SIZE(connmark_mt_reg)); + xt_unregister_match(&connmark_mt_reg); } module_init(connmark_mt_init); -- cgit v1.2.3-70-g09d2 From 9e05ec4b1804a1ba51f61fe169aef9b86edcd3f7 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 12 Jun 2009 18:56:14 +0200 Subject: netfilter: xtables: remove xt_conntrack v0 Superseded by xt_conntrack v1 (v2.6.24-2921-g64eb12f). Signed-off-by: Jan Engelhardt --- Documentation/feature-removal-schedule.txt | 3 - include/linux/netfilter/xt_conntrack.h | 36 ------- net/netfilter/xt_conntrack.c | 155 +---------------------------- 3 files changed, 1 insertion(+), 193 deletions(-) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 54f93579492..6746473ef03 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -238,9 +238,6 @@ What (Why): - "forwarding" header files like ipt_mac.h in include/linux/netfilter_ipv4/ and include/linux/netfilter_ipv6/ - - xt_conntrack match revision 0 - (superseded by xt_conntrack match revision 1) - - xt_iprange match revision 0, include/linux/netfilter_ipv4/ipt_iprange.h (superseded by xt_iprange match revision 1) diff --git a/include/linux/netfilter/xt_conntrack.h b/include/linux/netfilter/xt_conntrack.h index 7ae05338e94..54f47a2f615 100644 --- a/include/linux/netfilter/xt_conntrack.h +++ b/include/linux/netfilter/xt_conntrack.h @@ -32,42 +32,6 @@ enum { XT_CONNTRACK_DIRECTION = 1 << 12, }; -/* This is exposed to userspace, so remains frozen in time. */ -struct ip_conntrack_old_tuple -{ - struct { - __be32 ip; - union { - __u16 all; - } u; - } src; - - struct { - __be32 ip; - union { - __u16 all; - } u; - - /* The protocol. */ - __u16 protonum; - } dst; -}; - -struct xt_conntrack_info -{ - unsigned int statemask, statusmask; - - struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX]; - struct in_addr sipmsk[IP_CT_DIR_MAX], dipmsk[IP_CT_DIR_MAX]; - - unsigned long expires_min, expires_max; - - /* Flags word */ - __u8 flags; - /* Inverse flags */ - __u8 invflags; -}; - struct xt_conntrack_mtinfo1 { union nf_inet_addr origsrc_addr, origsrc_mask; union nf_inet_addr origdst_addr, origdst_mask; diff --git a/net/netfilter/xt_conntrack.c b/net/netfilter/xt_conntrack.c index fc581800698..6dc4652f2fe 100644 --- a/net/netfilter/xt_conntrack.c +++ b/net/netfilter/xt_conntrack.c @@ -19,100 +19,11 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Marc Boucher "); -MODULE_AUTHOR("Jan Engelhardt "); +MODULE_AUTHOR("Jan Engelhardt "); MODULE_DESCRIPTION("Xtables: connection tracking state match"); MODULE_ALIAS("ipt_conntrack"); MODULE_ALIAS("ip6t_conntrack"); -static bool -conntrack_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) -{ - const struct xt_conntrack_info *sinfo = par->matchinfo; - const struct nf_conn *ct; - enum ip_conntrack_info ctinfo; - unsigned int statebit; - - ct = nf_ct_get(skb, &ctinfo); - -#define FWINV(bool, invflg) ((bool) ^ !!(sinfo->invflags & (invflg))) - - if (ct == &nf_conntrack_untracked) - statebit = XT_CONNTRACK_STATE_UNTRACKED; - else if (ct) - statebit = XT_CONNTRACK_STATE_BIT(ctinfo); - else - statebit = XT_CONNTRACK_STATE_INVALID; - - if (sinfo->flags & XT_CONNTRACK_STATE) { - if (ct) { - if (test_bit(IPS_SRC_NAT_BIT, &ct->status)) - statebit |= XT_CONNTRACK_STATE_SNAT; - if (test_bit(IPS_DST_NAT_BIT, &ct->status)) - statebit |= XT_CONNTRACK_STATE_DNAT; - } - if (FWINV((statebit & sinfo->statemask) == 0, - XT_CONNTRACK_STATE)) - return false; - } - - if (ct == NULL) { - if (sinfo->flags & ~XT_CONNTRACK_STATE) - return false; - return true; - } - - if (sinfo->flags & XT_CONNTRACK_PROTO && - FWINV(nf_ct_protonum(ct) != - sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, - XT_CONNTRACK_PROTO)) - return false; - - if (sinfo->flags & XT_CONNTRACK_ORIGSRC && - FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip & - sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != - sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, - XT_CONNTRACK_ORIGSRC)) - return false; - - if (sinfo->flags & XT_CONNTRACK_ORIGDST && - FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip & - sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != - sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, - XT_CONNTRACK_ORIGDST)) - return false; - - if (sinfo->flags & XT_CONNTRACK_REPLSRC && - FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip & - sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != - sinfo->tuple[IP_CT_DIR_REPLY].src.ip, - XT_CONNTRACK_REPLSRC)) - return false; - - if (sinfo->flags & XT_CONNTRACK_REPLDST && - FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip & - sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != - sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, - XT_CONNTRACK_REPLDST)) - return false; - - if (sinfo->flags & XT_CONNTRACK_STATUS && - FWINV((ct->status & sinfo->statusmask) == 0, - XT_CONNTRACK_STATUS)) - return false; - - if(sinfo->flags & XT_CONNTRACK_EXPIRES) { - unsigned long expires = timer_pending(&ct->timeout) ? - (ct->timeout.expires - jiffies)/HZ : 0; - - if (FWINV(!(expires >= sinfo->expires_min && - expires <= sinfo->expires_max), - XT_CONNTRACK_EXPIRES)) - return false; - } - return true; -#undef FWINV -} - static bool conntrack_addrcmp(const union nf_inet_addr *kaddr, const union nf_inet_addr *uaddr, @@ -337,71 +248,7 @@ static void conntrack_mt_destroy_v1(const struct xt_mtdtor_param *par) conntrack_mt_destroy(par); } -#ifdef CONFIG_COMPAT -struct compat_xt_conntrack_info -{ - compat_uint_t statemask; - compat_uint_t statusmask; - struct ip_conntrack_old_tuple tuple[IP_CT_DIR_MAX]; - struct in_addr sipmsk[IP_CT_DIR_MAX]; - struct in_addr dipmsk[IP_CT_DIR_MAX]; - compat_ulong_t expires_min; - compat_ulong_t expires_max; - u_int8_t flags; - u_int8_t invflags; -}; - -static void conntrack_mt_compat_from_user_v0(void *dst, void *src) -{ - const struct compat_xt_conntrack_info *cm = src; - struct xt_conntrack_info m = { - .statemask = cm->statemask, - .statusmask = cm->statusmask, - .expires_min = cm->expires_min, - .expires_max = cm->expires_max, - .flags = cm->flags, - .invflags = cm->invflags, - }; - memcpy(m.tuple, cm->tuple, sizeof(m.tuple)); - memcpy(m.sipmsk, cm->sipmsk, sizeof(m.sipmsk)); - memcpy(m.dipmsk, cm->dipmsk, sizeof(m.dipmsk)); - memcpy(dst, &m, sizeof(m)); -} - -static int conntrack_mt_compat_to_user_v0(void __user *dst, void *src) -{ - const struct xt_conntrack_info *m = src; - struct compat_xt_conntrack_info cm = { - .statemask = m->statemask, - .statusmask = m->statusmask, - .expires_min = m->expires_min, - .expires_max = m->expires_max, - .flags = m->flags, - .invflags = m->invflags, - }; - memcpy(cm.tuple, m->tuple, sizeof(cm.tuple)); - memcpy(cm.sipmsk, m->sipmsk, sizeof(cm.sipmsk)); - memcpy(cm.dipmsk, m->dipmsk, sizeof(cm.dipmsk)); - return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; -} -#endif - static struct xt_match conntrack_mt_reg[] __read_mostly = { - { - .name = "conntrack", - .revision = 0, - .family = NFPROTO_IPV4, - .match = conntrack_mt_v0, - .checkentry = conntrack_mt_check, - .destroy = conntrack_mt_destroy, - .matchsize = sizeof(struct xt_conntrack_info), - .me = THIS_MODULE, -#ifdef CONFIG_COMPAT - .compatsize = sizeof(struct compat_xt_conntrack_info), - .compat_from_user = conntrack_mt_compat_from_user_v0, - .compat_to_user = conntrack_mt_compat_to_user_v0, -#endif - }, { .name = "conntrack", .revision = 1, -- cgit v1.2.3-70-g09d2 From 36d4084dc8eb7a9a3655a2041097a46aff3061e9 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 12 Jun 2009 18:58:19 +0200 Subject: netfilter: xtables: remove xt_iprange v0 Superseded by xt_iprange v1 (v2.6.24-2928-g1a50c5a1). Signed-off-by: Jan Engelhardt --- Documentation/feature-removal-schedule.txt | 4 --- include/linux/netfilter_ipv4/Kbuild | 1 - include/linux/netfilter_ipv4/ipt_iprange.h | 21 -------------- net/netfilter/xt_iprange.c | 45 ++---------------------------- 4 files changed, 2 insertions(+), 69 deletions(-) delete mode 100644 include/linux/netfilter_ipv4/ipt_iprange.h (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 6746473ef03..8862b037f0a 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -238,10 +238,6 @@ What (Why): - "forwarding" header files like ipt_mac.h in include/linux/netfilter_ipv4/ and include/linux/netfilter_ipv6/ - - xt_iprange match revision 0, - include/linux/netfilter_ipv4/ipt_iprange.h - (superseded by xt_iprange match revision 1) - - xt_mark match revision 0 (superseded by xt_mark match revision 1) diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild index 86d81a285f9..5e361ef44e8 100644 --- a/include/linux/netfilter_ipv4/Kbuild +++ b/include/linux/netfilter_ipv4/Kbuild @@ -23,7 +23,6 @@ header-y += ipt_ecn.h header-y += ipt_esp.h header-y += ipt_hashlimit.h header-y += ipt_helper.h -header-y += ipt_iprange.h header-y += ipt_length.h header-y += ipt_limit.h header-y += ipt_mac.h diff --git a/include/linux/netfilter_ipv4/ipt_iprange.h b/include/linux/netfilter_ipv4/ipt_iprange.h deleted file mode 100644 index 5f1aebde4d2..00000000000 --- a/include/linux/netfilter_ipv4/ipt_iprange.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _IPT_IPRANGE_H -#define _IPT_IPRANGE_H - -#include -#include - -struct ipt_iprange { - /* Inclusive: network order. */ - __be32 min_ip, max_ip; -}; - -struct ipt_iprange_info -{ - struct ipt_iprange src; - struct ipt_iprange dst; - - /* Flags from above */ - u_int8_t flags; -}; - -#endif /* _IPT_IPRANGE_H */ diff --git a/net/netfilter/xt_iprange.c b/net/netfilter/xt_iprange.c index 501f9b62318..ffc96387d55 100644 --- a/net/netfilter/xt_iprange.c +++ b/net/netfilter/xt_iprange.c @@ -14,40 +14,6 @@ #include #include #include -#include - -static bool -iprange_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) -{ - const struct ipt_iprange_info *info = par->matchinfo; - const struct iphdr *iph = ip_hdr(skb); - - if (info->flags & IPRANGE_SRC) { - if ((ntohl(iph->saddr) < ntohl(info->src.min_ip) - || ntohl(iph->saddr) > ntohl(info->src.max_ip)) - ^ !!(info->flags & IPRANGE_SRC_INV)) { - pr_debug("src IP %pI4 NOT in range %s%pI4-%pI4\n", - &iph->saddr, - info->flags & IPRANGE_SRC_INV ? "(INV) " : "", - &info->src.min_ip, - &info->src.max_ip); - return false; - } - } - if (info->flags & IPRANGE_DST) { - if ((ntohl(iph->daddr) < ntohl(info->dst.min_ip) - || ntohl(iph->daddr) > ntohl(info->dst.max_ip)) - ^ !!(info->flags & IPRANGE_DST_INV)) { - pr_debug("dst IP %pI4 NOT in range %s%pI4-%pI4\n", - &iph->daddr, - info->flags & IPRANGE_DST_INV ? "(INV) " : "", - &info->dst.min_ip, - &info->dst.max_ip); - return false; - } - } - return true; -} static bool iprange_mt4(const struct sk_buff *skb, const struct xt_match_param *par) @@ -125,14 +91,6 @@ iprange_mt6(const struct sk_buff *skb, const struct xt_match_param *par) } static struct xt_match iprange_mt_reg[] __read_mostly = { - { - .name = "iprange", - .revision = 0, - .family = NFPROTO_IPV4, - .match = iprange_mt_v0, - .matchsize = sizeof(struct ipt_iprange_info), - .me = THIS_MODULE, - }, { .name = "iprange", .revision = 1, @@ -164,7 +122,8 @@ static void __exit iprange_mt_exit(void) module_init(iprange_mt_init); module_exit(iprange_mt_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jozsef Kadlecsik , Jan Engelhardt "); +MODULE_AUTHOR("Jozsef Kadlecsik "); +MODULE_AUTHOR("Jan Engelhardt "); MODULE_DESCRIPTION("Xtables: arbitrary IPv4 range matching"); MODULE_ALIAS("ipt_iprange"); MODULE_ALIAS("ip6t_iprange"); -- cgit v1.2.3-70-g09d2 From 4725c7287ef2c4340cb433f59e40d143c1f43c22 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 12 Jun 2009 19:02:27 +0200 Subject: netfilter: xtables: remove xt_mark v0 Superseded by xt_mark v1 (v2.6.24-2922-g17b0d7e). Signed-off-by: Jan Engelhardt --- Documentation/feature-removal-schedule.txt | 3 -- include/linux/netfilter/xt_mark.h | 5 -- net/netfilter/xt_mark.c | 86 ++++-------------------------- 3 files changed, 10 insertions(+), 84 deletions(-) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 8862b037f0a..5556d2300be 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -238,9 +238,6 @@ What (Why): - "forwarding" header files like ipt_mac.h in include/linux/netfilter_ipv4/ and include/linux/netfilter_ipv6/ - - xt_mark match revision 0 - (superseded by xt_mark match revision 1) - - xt_recent: the old ipt_recent proc dir (superseded by /proc/net/xt_recent) diff --git a/include/linux/netfilter/xt_mark.h b/include/linux/netfilter/xt_mark.h index 6fa460a3cc2..6607c8f38ea 100644 --- a/include/linux/netfilter/xt_mark.h +++ b/include/linux/netfilter/xt_mark.h @@ -3,11 +3,6 @@ #include -struct xt_mark_info { - unsigned long mark, mask; - __u8 invert; -}; - struct xt_mark_mtinfo1 { __u32 mark, mask; __u8 invert; diff --git a/net/netfilter/xt_mark.c b/net/netfilter/xt_mark.c index 10b9e34bbc5..1db07d8125f 100644 --- a/net/netfilter/xt_mark.c +++ b/net/netfilter/xt_mark.c @@ -3,7 +3,7 @@ * * (C) 1999-2001 Marc Boucher * Copyright © CC Computer Consultants GmbH, 2007 - 2008 - * Jan Engelhardt + * Jan Engelhardt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -22,14 +22,6 @@ MODULE_DESCRIPTION("Xtables: packet mark match"); MODULE_ALIAS("ipt_mark"); MODULE_ALIAS("ip6t_mark"); -static bool -mark_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) -{ - const struct xt_mark_info *info = par->matchinfo; - - return ((skb->mark & info->mask) == info->mark) ^ info->invert; -} - static bool mark_mt(const struct sk_buff *skb, const struct xt_match_param *par) { @@ -38,81 +30,23 @@ mark_mt(const struct sk_buff *skb, const struct xt_match_param *par) return ((skb->mark & info->mask) == info->mark) ^ info->invert; } -static bool mark_mt_check_v0(const struct xt_mtchk_param *par) -{ - const struct xt_mark_info *minfo = par->matchinfo; - - if (minfo->mark > 0xffffffff || minfo->mask > 0xffffffff) { - printk(KERN_WARNING "mark: only supports 32bit mark\n"); - return false; - } - return true; -} - -#ifdef CONFIG_COMPAT -struct compat_xt_mark_info { - compat_ulong_t mark, mask; - u_int8_t invert; - u_int8_t __pad1; - u_int16_t __pad2; -}; - -static void mark_mt_compat_from_user_v0(void *dst, void *src) -{ - const struct compat_xt_mark_info *cm = src; - struct xt_mark_info m = { - .mark = cm->mark, - .mask = cm->mask, - .invert = cm->invert, - }; - memcpy(dst, &m, sizeof(m)); -} - -static int mark_mt_compat_to_user_v0(void __user *dst, void *src) -{ - const struct xt_mark_info *m = src; - struct compat_xt_mark_info cm = { - .mark = m->mark, - .mask = m->mask, - .invert = m->invert, - }; - return copy_to_user(dst, &cm, sizeof(cm)) ? -EFAULT : 0; -} -#endif /* CONFIG_COMPAT */ - -static struct xt_match mark_mt_reg[] __read_mostly = { - { - .name = "mark", - .revision = 0, - .family = NFPROTO_UNSPEC, - .checkentry = mark_mt_check_v0, - .match = mark_mt_v0, - .matchsize = sizeof(struct xt_mark_info), -#ifdef CONFIG_COMPAT - .compatsize = sizeof(struct compat_xt_mark_info), - .compat_from_user = mark_mt_compat_from_user_v0, - .compat_to_user = mark_mt_compat_to_user_v0, -#endif - .me = THIS_MODULE, - }, - { - .name = "mark", - .revision = 1, - .family = NFPROTO_UNSPEC, - .match = mark_mt, - .matchsize = sizeof(struct xt_mark_mtinfo1), - .me = THIS_MODULE, - }, +static struct xt_match mark_mt_reg __read_mostly = { + .name = "mark", + .revision = 1, + .family = NFPROTO_UNSPEC, + .match = mark_mt, + .matchsize = sizeof(struct xt_mark_mtinfo1), + .me = THIS_MODULE, }; static int __init mark_mt_init(void) { - return xt_register_matches(mark_mt_reg, ARRAY_SIZE(mark_mt_reg)); + return xt_register_match(&mark_mt_reg); } static void __exit mark_mt_exit(void) { - xt_unregister_matches(mark_mt_reg, ARRAY_SIZE(mark_mt_reg)); + xt_unregister_match(&mark_mt_reg); } module_init(mark_mt_init); -- cgit v1.2.3-70-g09d2 From 93bb1e9d117bfc60306b2b8bd9e0fa7ba3c88636 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Fri, 12 Jun 2009 19:47:21 +0200 Subject: netfilter: xtables: remove redirecting header files When IPv4 and IPv6 matches were unified approx. 3.5 years ago, they received new header filenames (e.g. xt_CLASSIFY.h). Let's remove the old ones now. Signed-off-by: Jan Engelhardt --- Documentation/feature-removal-schedule.txt | 3 - include/linux/netfilter_ipv4/Kbuild | 28 ------- include/linux/netfilter_ipv4/ipt_CLASSIFY.h | 7 -- include/linux/netfilter_ipv4/ipt_CONNMARK.h | 19 ----- include/linux/netfilter_ipv4/ipt_DSCP.h | 18 ----- include/linux/netfilter_ipv4/ipt_ECN.h | 4 +- include/linux/netfilter_ipv4/ipt_MARK.h | 18 ----- include/linux/netfilter_ipv4/ipt_NFQUEUE.h | 16 ---- include/linux/netfilter_ipv4/ipt_TCPMSS.h | 9 --- include/linux/netfilter_ipv4/ipt_comment.h | 10 --- include/linux/netfilter_ipv4/ipt_connbytes.h | 18 ----- include/linux/netfilter_ipv4/ipt_connmark.h | 7 -- include/linux/netfilter_ipv4/ipt_conntrack.h | 28 ------- include/linux/netfilter_ipv4/ipt_dccp.h | 15 ---- include/linux/netfilter_ipv4/ipt_dscp.h | 21 ------ include/linux/netfilter_ipv4/ipt_ecn.h | 4 +- include/linux/netfilter_ipv4/ipt_esp.h | 10 --- include/linux/netfilter_ipv4/ipt_hashlimit.h | 14 ---- include/linux/netfilter_ipv4/ipt_helper.h | 7 -- include/linux/netfilter_ipv4/ipt_length.h | 7 -- include/linux/netfilter_ipv4/ipt_limit.h | 8 -- include/linux/netfilter_ipv4/ipt_mac.h | 7 -- include/linux/netfilter_ipv4/ipt_mark.h | 9 --- include/linux/netfilter_ipv4/ipt_multiport.h | 15 ---- include/linux/netfilter_ipv4/ipt_physdev.h | 17 ----- include/linux/netfilter_ipv4/ipt_pkttype.h | 7 -- include/linux/netfilter_ipv4/ipt_policy.h | 23 ------ include/linux/netfilter_ipv4/ipt_recent.h | 21 ------ include/linux/netfilter_ipv4/ipt_sctp.h | 105 -------------------------- include/linux/netfilter_ipv4/ipt_state.h | 15 ---- include/linux/netfilter_ipv4/ipt_string.h | 10 --- include/linux/netfilter_ipv4/ipt_tcpmss.h | 7 -- include/linux/netfilter_ipv6/Kbuild | 11 +-- include/linux/netfilter_ipv6/ip6t_MARK.h | 9 --- include/linux/netfilter_ipv6/ip6t_esp.h | 10 --- include/linux/netfilter_ipv6/ip6t_length.h | 8 -- include/linux/netfilter_ipv6/ip6t_limit.h | 8 -- include/linux/netfilter_ipv6/ip6t_mac.h | 7 -- include/linux/netfilter_ipv6/ip6t_mark.h | 9 --- include/linux/netfilter_ipv6/ip6t_multiport.h | 14 ---- include/linux/netfilter_ipv6/ip6t_physdev.h | 17 ----- include/linux/netfilter_ipv6/ip6t_policy.h | 23 ------ 42 files changed, 5 insertions(+), 618 deletions(-) delete mode 100644 include/linux/netfilter_ipv4/ipt_CLASSIFY.h delete mode 100644 include/linux/netfilter_ipv4/ipt_CONNMARK.h delete mode 100644 include/linux/netfilter_ipv4/ipt_DSCP.h delete mode 100644 include/linux/netfilter_ipv4/ipt_MARK.h delete mode 100644 include/linux/netfilter_ipv4/ipt_NFQUEUE.h delete mode 100644 include/linux/netfilter_ipv4/ipt_TCPMSS.h delete mode 100644 include/linux/netfilter_ipv4/ipt_comment.h delete mode 100644 include/linux/netfilter_ipv4/ipt_connbytes.h delete mode 100644 include/linux/netfilter_ipv4/ipt_connmark.h delete mode 100644 include/linux/netfilter_ipv4/ipt_conntrack.h delete mode 100644 include/linux/netfilter_ipv4/ipt_dccp.h delete mode 100644 include/linux/netfilter_ipv4/ipt_dscp.h delete mode 100644 include/linux/netfilter_ipv4/ipt_esp.h delete mode 100644 include/linux/netfilter_ipv4/ipt_hashlimit.h delete mode 100644 include/linux/netfilter_ipv4/ipt_helper.h delete mode 100644 include/linux/netfilter_ipv4/ipt_length.h delete mode 100644 include/linux/netfilter_ipv4/ipt_limit.h delete mode 100644 include/linux/netfilter_ipv4/ipt_mac.h delete mode 100644 include/linux/netfilter_ipv4/ipt_mark.h delete mode 100644 include/linux/netfilter_ipv4/ipt_multiport.h delete mode 100644 include/linux/netfilter_ipv4/ipt_physdev.h delete mode 100644 include/linux/netfilter_ipv4/ipt_pkttype.h delete mode 100644 include/linux/netfilter_ipv4/ipt_policy.h delete mode 100644 include/linux/netfilter_ipv4/ipt_recent.h delete mode 100644 include/linux/netfilter_ipv4/ipt_sctp.h delete mode 100644 include/linux/netfilter_ipv4/ipt_state.h delete mode 100644 include/linux/netfilter_ipv4/ipt_string.h delete mode 100644 include/linux/netfilter_ipv4/ipt_tcpmss.h delete mode 100644 include/linux/netfilter_ipv6/ip6t_MARK.h delete mode 100644 include/linux/netfilter_ipv6/ip6t_esp.h delete mode 100644 include/linux/netfilter_ipv6/ip6t_length.h delete mode 100644 include/linux/netfilter_ipv6/ip6t_limit.h delete mode 100644 include/linux/netfilter_ipv6/ip6t_mac.h delete mode 100644 include/linux/netfilter_ipv6/ip6t_mark.h delete mode 100644 include/linux/netfilter_ipv6/ip6t_multiport.h delete mode 100644 include/linux/netfilter_ipv6/ip6t_physdev.h delete mode 100644 include/linux/netfilter_ipv6/ip6t_policy.h (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 5556d2300be..698e1e8b304 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -235,9 +235,6 @@ Who: Thomas Gleixner --------------------------- What (Why): - - "forwarding" header files like ipt_mac.h in - include/linux/netfilter_ipv4/ and include/linux/netfilter_ipv6/ - - xt_recent: the old ipt_recent proc dir (superseded by /proc/net/xt_recent) diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild index 541300531cb..431b4076192 100644 --- a/include/linux/netfilter_ipv4/Kbuild +++ b/include/linux/netfilter_ipv4/Kbuild @@ -1,42 +1,14 @@ -header-y += ipt_CLASSIFY.h header-y += ipt_CLUSTERIP.h -header-y += ipt_CONNMARK.h -header-y += ipt_DSCP.h header-y += ipt_ECN.h header-y += ipt_LOG.h -header-y += ipt_MARK.h -header-y += ipt_NFQUEUE.h header-y += ipt_REJECT.h header-y += ipt_SAME.h -header-y += ipt_TCPMSS.h header-y += ipt_TTL.h header-y += ipt_ULOG.h header-y += ipt_addrtype.h header-y += ipt_ah.h -header-y += ipt_comment.h -header-y += ipt_connbytes.h -header-y += ipt_connmark.h -header-y += ipt_conntrack.h -header-y += ipt_dccp.h -header-y += ipt_dscp.h header-y += ipt_ecn.h -header-y += ipt_esp.h -header-y += ipt_hashlimit.h -header-y += ipt_helper.h -header-y += ipt_length.h -header-y += ipt_limit.h -header-y += ipt_mac.h -header-y += ipt_mark.h -header-y += ipt_multiport.h -header-y += ipt_physdev.h -header-y += ipt_pkttype.h -header-y += ipt_policy.h header-y += ipt_realm.h -header-y += ipt_recent.h -header-y += ipt_sctp.h -header-y += ipt_state.h -header-y += ipt_string.h -header-y += ipt_tcpmss.h header-y += ipt_ttl.h unifdef-y += ip_queue.h diff --git a/include/linux/netfilter_ipv4/ipt_CLASSIFY.h b/include/linux/netfilter_ipv4/ipt_CLASSIFY.h deleted file mode 100644 index a46d511b5c3..00000000000 --- a/include/linux/netfilter_ipv4/ipt_CLASSIFY.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _IPT_CLASSIFY_H -#define _IPT_CLASSIFY_H - -#include -#define ipt_classify_target_info xt_classify_target_info - -#endif /*_IPT_CLASSIFY_H */ diff --git a/include/linux/netfilter_ipv4/ipt_CONNMARK.h b/include/linux/netfilter_ipv4/ipt_CONNMARK.h deleted file mode 100644 index 9ecfee0a9e3..00000000000 --- a/include/linux/netfilter_ipv4/ipt_CONNMARK.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _IPT_CONNMARK_H_target -#define _IPT_CONNMARK_H_target - -/* Copyright (C) 2002,2004 MARA Systems AB - * by Henrik Nordstrom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#include -#define IPT_CONNMARK_SET XT_CONNMARK_SET -#define IPT_CONNMARK_SAVE XT_CONNMARK_SAVE -#define IPT_CONNMARK_RESTORE XT_CONNMARK_RESTORE - -#define ipt_connmark_target_info xt_connmark_target_info - -#endif /*_IPT_CONNMARK_H_target*/ diff --git a/include/linux/netfilter_ipv4/ipt_DSCP.h b/include/linux/netfilter_ipv4/ipt_DSCP.h deleted file mode 100644 index 3491e524d5e..00000000000 --- a/include/linux/netfilter_ipv4/ipt_DSCP.h +++ /dev/null @@ -1,18 +0,0 @@ -/* iptables module for setting the IPv4 DSCP field - * - * (C) 2002 Harald Welte - * based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh - * This software is distributed under GNU GPL v2, 1991 - * - * See RFC2474 for a description of the DSCP field within the IP Header. - * - * ipt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp -*/ -#ifndef _IPT_DSCP_TARGET_H -#define _IPT_DSCP_TARGET_H -#include -#include - -#define ipt_DSCP_info xt_DSCP_info - -#endif /* _IPT_DSCP_TARGET_H */ diff --git a/include/linux/netfilter_ipv4/ipt_ECN.h b/include/linux/netfilter_ipv4/ipt_ECN.h index 94e0d986646..7ca45918ab8 100644 --- a/include/linux/netfilter_ipv4/ipt_ECN.h +++ b/include/linux/netfilter_ipv4/ipt_ECN.h @@ -8,9 +8,9 @@ */ #ifndef _IPT_ECN_TARGET_H #define _IPT_ECN_TARGET_H -#include +#include -#define IPT_ECN_IP_MASK (~IPT_DSCP_MASK) +#define IPT_ECN_IP_MASK (~XT_DSCP_MASK) #define IPT_ECN_OP_SET_IP 0x01 /* set ECN bits of IPv4 header */ #define IPT_ECN_OP_SET_ECE 0x10 /* set ECE bit of TCP header */ diff --git a/include/linux/netfilter_ipv4/ipt_MARK.h b/include/linux/netfilter_ipv4/ipt_MARK.h deleted file mode 100644 index 697a486a96d..00000000000 --- a/include/linux/netfilter_ipv4/ipt_MARK.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _IPT_MARK_H_target -#define _IPT_MARK_H_target - -/* Backwards compatibility for old userspace */ - -#include - -/* Version 0 */ -#define ipt_mark_target_info xt_mark_target_info - -/* Version 1 */ -#define IPT_MARK_SET XT_MARK_SET -#define IPT_MARK_AND XT_MARK_AND -#define IPT_MARK_OR XT_MARK_OR - -#define ipt_mark_target_info_v1 xt_mark_target_info_v1 - -#endif /*_IPT_MARK_H_target*/ diff --git a/include/linux/netfilter_ipv4/ipt_NFQUEUE.h b/include/linux/netfilter_ipv4/ipt_NFQUEUE.h deleted file mode 100644 index 97a2a7557cb..00000000000 --- a/include/linux/netfilter_ipv4/ipt_NFQUEUE.h +++ /dev/null @@ -1,16 +0,0 @@ -/* iptables module for using NFQUEUE mechanism - * - * (C) 2005 Harald Welte - * - * This software is distributed under GNU GPL v2, 1991 - * -*/ -#ifndef _IPT_NFQ_TARGET_H -#define _IPT_NFQ_TARGET_H - -/* Backwards compatibility for old userspace */ -#include - -#define ipt_NFQ_info xt_NFQ_info - -#endif /* _IPT_DSCP_TARGET_H */ diff --git a/include/linux/netfilter_ipv4/ipt_TCPMSS.h b/include/linux/netfilter_ipv4/ipt_TCPMSS.h deleted file mode 100644 index 7a850f94582..00000000000 --- a/include/linux/netfilter_ipv4/ipt_TCPMSS.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _IPT_TCPMSS_H -#define _IPT_TCPMSS_H - -#include - -#define ipt_tcpmss_info xt_tcpmss_info -#define IPT_TCPMSS_CLAMP_PMTU XT_TCPMSS_CLAMP_PMTU - -#endif /*_IPT_TCPMSS_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_comment.h b/include/linux/netfilter_ipv4/ipt_comment.h deleted file mode 100644 index ae2afc2f748..00000000000 --- a/include/linux/netfilter_ipv4/ipt_comment.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _IPT_COMMENT_H -#define _IPT_COMMENT_H - -#include - -#define IPT_MAX_COMMENT_LEN XT_MAX_COMMENT_LEN - -#define ipt_comment_info xt_comment_info - -#endif /* _IPT_COMMENT_H */ diff --git a/include/linux/netfilter_ipv4/ipt_connbytes.h b/include/linux/netfilter_ipv4/ipt_connbytes.h deleted file mode 100644 index f63e6ee9111..00000000000 --- a/include/linux/netfilter_ipv4/ipt_connbytes.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _IPT_CONNBYTES_H -#define _IPT_CONNBYTES_H - -#include -#define ipt_connbytes_what xt_connbytes_what - -#define IPT_CONNBYTES_PKTS XT_CONNBYTES_PKTS -#define IPT_CONNBYTES_BYTES XT_CONNBYTES_BYTES -#define IPT_CONNBYTES_AVGPKT XT_CONNBYTES_AVGPKT - -#define ipt_connbytes_direction xt_connbytes_direction -#define IPT_CONNBYTES_DIR_ORIGINAL XT_CONNBYTES_DIR_ORIGINAL -#define IPT_CONNBYTES_DIR_REPLY XT_CONNBYTES_DIR_REPLY -#define IPT_CONNBYTES_DIR_BOTH XT_CONNBYTES_DIR_BOTH - -#define ipt_connbytes_info xt_connbytes_info - -#endif diff --git a/include/linux/netfilter_ipv4/ipt_connmark.h b/include/linux/netfilter_ipv4/ipt_connmark.h deleted file mode 100644 index c7ba6560d44..00000000000 --- a/include/linux/netfilter_ipv4/ipt_connmark.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _IPT_CONNMARK_H -#define _IPT_CONNMARK_H - -#include -#define ipt_connmark_info xt_connmark_info - -#endif /*_IPT_CONNMARK_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_conntrack.h b/include/linux/netfilter_ipv4/ipt_conntrack.h deleted file mode 100644 index cde6762949c..00000000000 --- a/include/linux/netfilter_ipv4/ipt_conntrack.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Header file for kernel module to match connection tracking information. - * GPL (C) 2001 Marc Boucher (marc@mbsi.ca). - */ - -#ifndef _IPT_CONNTRACK_H -#define _IPT_CONNTRACK_H - -#include - -#define IPT_CONNTRACK_STATE_BIT(ctinfo) XT_CONNTRACK_STATE_BIT(ctinfo) -#define IPT_CONNTRACK_STATE_INVALID XT_CONNTRACK_STATE_INVALID - -#define IPT_CONNTRACK_STATE_SNAT XT_CONNTRACK_STATE_SNAT -#define IPT_CONNTRACK_STATE_DNAT XT_CONNTRACK_STATE_DNAT -#define IPT_CONNTRACK_STATE_UNTRACKED XT_CONNTRACK_STATE_UNTRACKED - -/* flags, invflags: */ -#define IPT_CONNTRACK_STATE XT_CONNTRACK_STATE -#define IPT_CONNTRACK_PROTO XT_CONNTRACK_PROTO -#define IPT_CONNTRACK_ORIGSRC XT_CONNTRACK_ORIGSRC -#define IPT_CONNTRACK_ORIGDST XT_CONNTRACK_ORIGDST -#define IPT_CONNTRACK_REPLSRC XT_CONNTRACK_REPLSRC -#define IPT_CONNTRACK_REPLDST XT_CONNTRACK_REPLDST -#define IPT_CONNTRACK_STATUS XT_CONNTRACK_STATUS -#define IPT_CONNTRACK_EXPIRES XT_CONNTRACK_EXPIRES - -#define ipt_conntrack_info xt_conntrack_info -#endif /*_IPT_CONNTRACK_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_dccp.h b/include/linux/netfilter_ipv4/ipt_dccp.h deleted file mode 100644 index e70d11e1f53..00000000000 --- a/include/linux/netfilter_ipv4/ipt_dccp.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _IPT_DCCP_H_ -#define _IPT_DCCP_H_ - -#include -#define IPT_DCCP_SRC_PORTS XT_DCCP_SRC_PORTS -#define IPT_DCCP_DEST_PORTS XT_DCCP_DEST_PORTS -#define IPT_DCCP_TYPE XT_DCCP_TYPE -#define IPT_DCCP_OPTION XT_DCCP_OPTION - -#define IPT_DCCP_VALID_FLAGS XT_DCCP_VALID_FLAGS - -#define ipt_dccp_info xt_dccp_info - -#endif /* _IPT_DCCP_H_ */ - diff --git a/include/linux/netfilter_ipv4/ipt_dscp.h b/include/linux/netfilter_ipv4/ipt_dscp.h deleted file mode 100644 index 4b82ca912b0..00000000000 --- a/include/linux/netfilter_ipv4/ipt_dscp.h +++ /dev/null @@ -1,21 +0,0 @@ -/* iptables module for matching the IPv4 DSCP field - * - * (C) 2002 Harald Welte - * This software is distributed under GNU GPL v2, 1991 - * - * See RFC2474 for a description of the DSCP field within the IP Header. - * - * ipt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp -*/ -#ifndef _IPT_DSCP_H -#define _IPT_DSCP_H - -#include - -#define IPT_DSCP_MASK XT_DSCP_MASK -#define IPT_DSCP_SHIFT XT_DSCP_SHIFT -#define IPT_DSCP_MAX XT_DSCP_MAX - -#define ipt_dscp_info xt_dscp_info - -#endif /* _IPT_DSCP_H */ diff --git a/include/linux/netfilter_ipv4/ipt_ecn.h b/include/linux/netfilter_ipv4/ipt_ecn.h index 1f0d9a4d337..9945baa4ccd 100644 --- a/include/linux/netfilter_ipv4/ipt_ecn.h +++ b/include/linux/netfilter_ipv4/ipt_ecn.h @@ -8,9 +8,9 @@ */ #ifndef _IPT_ECN_H #define _IPT_ECN_H -#include +#include -#define IPT_ECN_IP_MASK (~IPT_DSCP_MASK) +#define IPT_ECN_IP_MASK (~XT_DSCP_MASK) #define IPT_ECN_OP_MATCH_IP 0x01 #define IPT_ECN_OP_MATCH_ECE 0x10 diff --git a/include/linux/netfilter_ipv4/ipt_esp.h b/include/linux/netfilter_ipv4/ipt_esp.h deleted file mode 100644 index 78296e7eeff..00000000000 --- a/include/linux/netfilter_ipv4/ipt_esp.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _IPT_ESP_H -#define _IPT_ESP_H - -#include - -#define ipt_esp xt_esp -#define IPT_ESP_INV_SPI XT_ESP_INV_SPI -#define IPT_ESP_INV_MASK XT_ESP_INV_MASK - -#endif /*_IPT_ESP_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_hashlimit.h b/include/linux/netfilter_ipv4/ipt_hashlimit.h deleted file mode 100644 index 5662120a3d7..00000000000 --- a/include/linux/netfilter_ipv4/ipt_hashlimit.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _IPT_HASHLIMIT_H -#define _IPT_HASHLIMIT_H - -#include - -#define IPT_HASHLIMIT_SCALE XT_HASHLIMIT_SCALE -#define IPT_HASHLIMIT_HASH_DIP XT_HASHLIMIT_HASH_DIP -#define IPT_HASHLIMIT_HASH_DPT XT_HASHLIMIT_HASH_DPT -#define IPT_HASHLIMIT_HASH_SIP XT_HASHLIMIT_HASH_SIP -#define IPT_HASHLIMIT_HASH_SPT XT_HASHLIMIT_HASH_SPT - -#define ipt_hashlimit_info xt_hashlimit_info - -#endif /* _IPT_HASHLIMIT_H */ diff --git a/include/linux/netfilter_ipv4/ipt_helper.h b/include/linux/netfilter_ipv4/ipt_helper.h deleted file mode 100644 index 80452c21855..00000000000 --- a/include/linux/netfilter_ipv4/ipt_helper.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _IPT_HELPER_H -#define _IPT_HELPER_H - -#include -#define ipt_helper_info xt_helper_info - -#endif /* _IPT_HELPER_H */ diff --git a/include/linux/netfilter_ipv4/ipt_length.h b/include/linux/netfilter_ipv4/ipt_length.h deleted file mode 100644 index 9b45206ffce..00000000000 --- a/include/linux/netfilter_ipv4/ipt_length.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _IPT_LENGTH_H -#define _IPT_LENGTH_H - -#include -#define ipt_length_info xt_length_info - -#endif /*_IPT_LENGTH_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_limit.h b/include/linux/netfilter_ipv4/ipt_limit.h deleted file mode 100644 index 92f5cd07bbc..00000000000 --- a/include/linux/netfilter_ipv4/ipt_limit.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _IPT_RATE_H -#define _IPT_RATE_H - -#include -#define IPT_LIMIT_SCALE XT_LIMIT_SCALE -#define ipt_rateinfo xt_rateinfo - -#endif /*_IPT_RATE_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_mac.h b/include/linux/netfilter_ipv4/ipt_mac.h deleted file mode 100644 index b186008a3c4..00000000000 --- a/include/linux/netfilter_ipv4/ipt_mac.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _IPT_MAC_H -#define _IPT_MAC_H - -#include -#define ipt_mac_info xt_mac_info - -#endif /*_IPT_MAC_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_mark.h b/include/linux/netfilter_ipv4/ipt_mark.h deleted file mode 100644 index bfde67c6122..00000000000 --- a/include/linux/netfilter_ipv4/ipt_mark.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _IPT_MARK_H -#define _IPT_MARK_H - -/* Backwards compatibility for old userspace */ -#include - -#define ipt_mark_info xt_mark_info - -#endif /*_IPT_MARK_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_multiport.h b/include/linux/netfilter_ipv4/ipt_multiport.h deleted file mode 100644 index 55fe85eca88..00000000000 --- a/include/linux/netfilter_ipv4/ipt_multiport.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _IPT_MULTIPORT_H -#define _IPT_MULTIPORT_H - -#include - -#define IPT_MULTIPORT_SOURCE XT_MULTIPORT_SOURCE -#define IPT_MULTIPORT_DESTINATION XT_MULTIPORT_DESTINATION -#define IPT_MULTIPORT_EITHER XT_MULTIPORT_EITHER - -#define IPT_MULTI_PORTS XT_MULTI_PORTS - -#define ipt_multiport xt_multiport -#define ipt_multiport_v1 xt_multiport_v1 - -#endif /*_IPT_MULTIPORT_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_physdev.h b/include/linux/netfilter_ipv4/ipt_physdev.h deleted file mode 100644 index 2400e7140f2..00000000000 --- a/include/linux/netfilter_ipv4/ipt_physdev.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _IPT_PHYSDEV_H -#define _IPT_PHYSDEV_H - -/* Backwards compatibility for old userspace */ - -#include - -#define IPT_PHYSDEV_OP_IN XT_PHYSDEV_OP_IN -#define IPT_PHYSDEV_OP_OUT XT_PHYSDEV_OP_OUT -#define IPT_PHYSDEV_OP_BRIDGED XT_PHYSDEV_OP_BRIDGED -#define IPT_PHYSDEV_OP_ISIN XT_PHYSDEV_OP_ISIN -#define IPT_PHYSDEV_OP_ISOUT XT_PHYSDEV_OP_ISOUT -#define IPT_PHYSDEV_OP_MASK XT_PHYSDEV_OP_MASK - -#define ipt_physdev_info xt_physdev_info - -#endif /*_IPT_PHYSDEV_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_pkttype.h b/include/linux/netfilter_ipv4/ipt_pkttype.h deleted file mode 100644 index ff1fbc949a0..00000000000 --- a/include/linux/netfilter_ipv4/ipt_pkttype.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _IPT_PKTTYPE_H -#define _IPT_PKTTYPE_H - -#include -#define ipt_pkttype_info xt_pkttype_info - -#endif /*_IPT_PKTTYPE_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_policy.h b/include/linux/netfilter_ipv4/ipt_policy.h deleted file mode 100644 index 1037fb2cd20..00000000000 --- a/include/linux/netfilter_ipv4/ipt_policy.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _IPT_POLICY_H -#define _IPT_POLICY_H - -#include - -#define IPT_POLICY_MAX_ELEM XT_POLICY_MAX_ELEM - -/* ipt_policy_flags */ -#define IPT_POLICY_MATCH_IN XT_POLICY_MATCH_IN -#define IPT_POLICY_MATCH_OUT XT_POLICY_MATCH_OUT -#define IPT_POLICY_MATCH_NONE XT_POLICY_MATCH_NONE -#define IPT_POLICY_MATCH_STRICT XT_POLICY_MATCH_STRICT - -/* ipt_policy_modes */ -#define IPT_POLICY_MODE_TRANSPORT XT_POLICY_MODE_TRANSPORT -#define IPT_POLICY_MODE_TUNNEL XT_POLICY_MODE_TUNNEL - -#define ipt_policy_spec xt_policy_spec -#define ipt_policy_addr xt_policy_addr -#define ipt_policy_elem xt_policy_elem -#define ipt_policy_info xt_policy_info - -#endif /* _IPT_POLICY_H */ diff --git a/include/linux/netfilter_ipv4/ipt_recent.h b/include/linux/netfilter_ipv4/ipt_recent.h deleted file mode 100644 index d636cca133c..00000000000 --- a/include/linux/netfilter_ipv4/ipt_recent.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _IPT_RECENT_H -#define _IPT_RECENT_H - -#include - -#define ipt_recent_info xt_recent_mtinfo - -enum { - IPT_RECENT_CHECK = XT_RECENT_CHECK, - IPT_RECENT_SET = XT_RECENT_SET, - IPT_RECENT_UPDATE = XT_RECENT_UPDATE, - IPT_RECENT_REMOVE = XT_RECENT_REMOVE, - IPT_RECENT_TTL = XT_RECENT_TTL, - - IPT_RECENT_SOURCE = XT_RECENT_SOURCE, - IPT_RECENT_DEST = XT_RECENT_DEST, - - IPT_RECENT_NAME_LEN = XT_RECENT_NAME_LEN, -}; - -#endif /*_IPT_RECENT_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_sctp.h b/include/linux/netfilter_ipv4/ipt_sctp.h deleted file mode 100644 index 80b3dbacd19..00000000000 --- a/include/linux/netfilter_ipv4/ipt_sctp.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef _IPT_SCTP_H_ -#define _IPT_SCTP_H_ - -#define IPT_SCTP_SRC_PORTS 0x01 -#define IPT_SCTP_DEST_PORTS 0x02 -#define IPT_SCTP_CHUNK_TYPES 0x04 - -#define IPT_SCTP_VALID_FLAGS 0x07 - - -struct ipt_sctp_flag_info { - u_int8_t chunktype; - u_int8_t flag; - u_int8_t flag_mask; -}; - -#define IPT_NUM_SCTP_FLAGS 4 - -struct ipt_sctp_info { - u_int16_t dpts[2]; /* Min, Max */ - u_int16_t spts[2]; /* Min, Max */ - - u_int32_t chunkmap[256 / sizeof (u_int32_t)]; /* Bit mask of chunks to be matched according to RFC 2960 */ - -#define SCTP_CHUNK_MATCH_ANY 0x01 /* Match if any of the chunk types are present */ -#define SCTP_CHUNK_MATCH_ALL 0x02 /* Match if all of the chunk types are present */ -#define SCTP_CHUNK_MATCH_ONLY 0x04 /* Match if these are the only chunk types present */ - - u_int32_t chunk_match_type; - struct ipt_sctp_flag_info flag_info[IPT_NUM_SCTP_FLAGS]; - int flag_count; - - u_int32_t flags; - u_int32_t invflags; -}; - -#define bytes(type) (sizeof(type) * 8) - -#define SCTP_CHUNKMAP_SET(chunkmap, type) \ - do { \ - chunkmap[type / bytes(u_int32_t)] |= \ - 1 << (type % bytes(u_int32_t)); \ - } while (0) - -#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \ - do { \ - chunkmap[type / bytes(u_int32_t)] &= \ - ~(1 << (type % bytes(u_int32_t))); \ - } while (0) - -#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \ -({ \ - (chunkmap[type / bytes (u_int32_t)] & \ - (1 << (type % bytes (u_int32_t)))) ? 1: 0; \ -}) - -#define SCTP_CHUNKMAP_RESET(chunkmap) \ - do { \ - int i; \ - for (i = 0; i < ARRAY_SIZE(chunkmap); i++) \ - chunkmap[i] = 0; \ - } while (0) - -#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \ - do { \ - int i; \ - for (i = 0; i < ARRAY_SIZE(chunkmap); i++) \ - chunkmap[i] = ~0; \ - } while (0) - -#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \ - do { \ - int i; \ - for (i = 0; i < ARRAY_SIZE(chunkmap); i++) \ - destmap[i] = srcmap[i]; \ - } while (0) - -#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \ -({ \ - int i; \ - int flag = 1; \ - for (i = 0; i < ARRAY_SIZE(chunkmap); i++) { \ - if (chunkmap[i]) { \ - flag = 0; \ - break; \ - } \ - } \ - flag; \ -}) - -#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \ -({ \ - int i; \ - int flag = 1; \ - for (i = 0; i < ARRAY_SIZE(chunkmap); i++) { \ - if (chunkmap[i] != ~0) { \ - flag = 0; \ - break; \ - } \ - } \ - flag; \ -}) - -#endif /* _IPT_SCTP_H_ */ - diff --git a/include/linux/netfilter_ipv4/ipt_state.h b/include/linux/netfilter_ipv4/ipt_state.h deleted file mode 100644 index a44a99cc28c..00000000000 --- a/include/linux/netfilter_ipv4/ipt_state.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _IPT_STATE_H -#define _IPT_STATE_H - -/* Backwards compatibility for old userspace */ - -#include - -#define IPT_STATE_BIT XT_STATE_BIT -#define IPT_STATE_INVALID XT_STATE_INVALID - -#define IPT_STATE_UNTRACKED XT_STATE_UNTRACKED - -#define ipt_state_info xt_state_info - -#endif /*_IPT_STATE_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_string.h b/include/linux/netfilter_ipv4/ipt_string.h deleted file mode 100644 index c26de305990..00000000000 --- a/include/linux/netfilter_ipv4/ipt_string.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _IPT_STRING_H -#define _IPT_STRING_H - -#include - -#define IPT_STRING_MAX_PATTERN_SIZE XT_STRING_MAX_PATTERN_SIZE -#define IPT_STRING_MAX_ALGO_NAME_SIZE XT_STRING_MAX_ALGO_NAME_SIZE -#define ipt_string_info xt_string_info - -#endif /*_IPT_STRING_H*/ diff --git a/include/linux/netfilter_ipv4/ipt_tcpmss.h b/include/linux/netfilter_ipv4/ipt_tcpmss.h deleted file mode 100644 index 18bbc8e8e00..00000000000 --- a/include/linux/netfilter_ipv4/ipt_tcpmss.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _IPT_TCPMSS_MATCH_H -#define _IPT_TCPMSS_MATCH_H - -#include -#define ipt_tcpmss_match_info xt_tcpmss_match_info - -#endif /*_IPT_TCPMSS_MATCH_H*/ diff --git a/include/linux/netfilter_ipv6/Kbuild b/include/linux/netfilter_ipv6/Kbuild index 4610a16da0a..e864eaee9e5 100644 --- a/include/linux/netfilter_ipv6/Kbuild +++ b/include/linux/netfilter_ipv6/Kbuild @@ -1,21 +1,12 @@ header-y += ip6t_HL.h header-y += ip6t_LOG.h -header-y += ip6t_MARK.h header-y += ip6t_REJECT.h header-y += ip6t_ah.h -header-y += ip6t_esp.h header-y += ip6t_frag.h -header-y += ip6t_hl.h header-y += ip6t_ipv6header.h -header-y += ip6t_length.h -header-y += ip6t_limit.h -header-y += ip6t_mac.h -header-y += ip6t_mark.h +header-y += ip6t_hl.h header-y += ip6t_mh.h -header-y += ip6t_multiport.h header-y += ip6t_opts.h -header-y += ip6t_physdev.h -header-y += ip6t_policy.h header-y += ip6t_rt.h unifdef-y += ip6_tables.h diff --git a/include/linux/netfilter_ipv6/ip6t_MARK.h b/include/linux/netfilter_ipv6/ip6t_MARK.h deleted file mode 100644 index 7cf629a8ab9..00000000000 --- a/include/linux/netfilter_ipv6/ip6t_MARK.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _IP6T_MARK_H_target -#define _IP6T_MARK_H_target - -/* Backwards compatibility for old userspace */ -#include - -#define ip6t_mark_target_info xt_mark_target_info - -#endif /*_IP6T_MARK_H_target*/ diff --git a/include/linux/netfilter_ipv6/ip6t_esp.h b/include/linux/netfilter_ipv6/ip6t_esp.h deleted file mode 100644 index f62eaf53c16..00000000000 --- a/include/linux/netfilter_ipv6/ip6t_esp.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _IP6T_ESP_H -#define _IP6T_ESP_H - -#include - -#define ip6t_esp xt_esp -#define IP6T_ESP_INV_SPI XT_ESP_INV_SPI -#define IP6T_ESP_INV_MASK XT_ESP_INV_MASK - -#endif /*_IP6T_ESP_H*/ diff --git a/include/linux/netfilter_ipv6/ip6t_length.h b/include/linux/netfilter_ipv6/ip6t_length.h deleted file mode 100644 index 9e9689d03ed..00000000000 --- a/include/linux/netfilter_ipv6/ip6t_length.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _IP6T_LENGTH_H -#define _IP6T_LENGTH_H - -#include -#define ip6t_length_info xt_length_info - -#endif /*_IP6T_LENGTH_H*/ - diff --git a/include/linux/netfilter_ipv6/ip6t_limit.h b/include/linux/netfilter_ipv6/ip6t_limit.h deleted file mode 100644 index 487e5ea342c..00000000000 --- a/include/linux/netfilter_ipv6/ip6t_limit.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _IP6T_RATE_H -#define _IP6T_RATE_H - -#include -#define IP6T_LIMIT_SCALE XT_LIMIT_SCALE -#define ip6t_rateinfo xt_rateinfo - -#endif /*_IP6T_RATE_H*/ diff --git a/include/linux/netfilter_ipv6/ip6t_mac.h b/include/linux/netfilter_ipv6/ip6t_mac.h deleted file mode 100644 index ac58e83e942..00000000000 --- a/include/linux/netfilter_ipv6/ip6t_mac.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _IP6T_MAC_H -#define _IP6T_MAC_H - -#include -#define ip6t_mac_info xt_mac_info - -#endif /*_IP6T_MAC_H*/ diff --git a/include/linux/netfilter_ipv6/ip6t_mark.h b/include/linux/netfilter_ipv6/ip6t_mark.h deleted file mode 100644 index ff204951ddc..00000000000 --- a/include/linux/netfilter_ipv6/ip6t_mark.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _IP6T_MARK_H -#define _IP6T_MARK_H - -/* Backwards compatibility for old userspace */ -#include - -#define ip6t_mark_info xt_mark_info - -#endif /*_IPT_MARK_H*/ diff --git a/include/linux/netfilter_ipv6/ip6t_multiport.h b/include/linux/netfilter_ipv6/ip6t_multiport.h deleted file mode 100644 index 042c92661ce..00000000000 --- a/include/linux/netfilter_ipv6/ip6t_multiport.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _IP6T_MULTIPORT_H -#define _IP6T_MULTIPORT_H - -#include - -#define IP6T_MULTIPORT_SOURCE XT_MULTIPORT_SOURCE -#define IP6T_MULTIPORT_DESTINATION XT_MULTIPORT_DESTINATION -#define IP6T_MULTIPORT_EITHER XT_MULTIPORT_EITHER - -#define IP6T_MULTI_PORTS XT_MULTI_PORTS - -#define ip6t_multiport xt_multiport - -#endif /*_IP6T_MULTIPORT_H*/ diff --git a/include/linux/netfilter_ipv6/ip6t_physdev.h b/include/linux/netfilter_ipv6/ip6t_physdev.h deleted file mode 100644 index c161c0a81b5..00000000000 --- a/include/linux/netfilter_ipv6/ip6t_physdev.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _IP6T_PHYSDEV_H -#define _IP6T_PHYSDEV_H - -/* Backwards compatibility for old userspace */ - -#include - -#define IP6T_PHYSDEV_OP_IN XT_PHYSDEV_OP_IN -#define IP6T_PHYSDEV_OP_OUT XT_PHYSDEV_OP_OUT -#define IP6T_PHYSDEV_OP_BRIDGED XT_PHYSDEV_OP_BRIDGED -#define IP6T_PHYSDEV_OP_ISIN XT_PHYSDEV_OP_ISIN -#define IP6T_PHYSDEV_OP_ISOUT XT_PHYSDEV_OP_ISOUT -#define IP6T_PHYSDEV_OP_MASK XT_PHYSDEV_OP_MASK - -#define ip6t_physdev_info xt_physdev_info - -#endif /*_IP6T_PHYSDEV_H*/ diff --git a/include/linux/netfilter_ipv6/ip6t_policy.h b/include/linux/netfilter_ipv6/ip6t_policy.h deleted file mode 100644 index b1c449d7ec8..00000000000 --- a/include/linux/netfilter_ipv6/ip6t_policy.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _IP6T_POLICY_H -#define _IP6T_POLICY_H - -#include - -#define IP6T_POLICY_MAX_ELEM XT_POLICY_MAX_ELEM - -/* ip6t_policy_flags */ -#define IP6T_POLICY_MATCH_IN XT_POLICY_MATCH_IN -#define IP6T_POLICY_MATCH_OUT XT_POLICY_MATCH_OUT -#define IP6T_POLICY_MATCH_NONE XT_POLICY_MATCH_NONE -#define IP6T_POLICY_MATCH_STRICT XT_POLICY_MATCH_STRICT - -/* ip6t_policy_modes */ -#define IP6T_POLICY_MODE_TRANSPORT XT_POLICY_MODE_TRANSPORT -#define IP6T_POLICY_MODE_TUNNEL XT_POLICY_MODE_TUNNEL - -#define ip6t_policy_spec xt_policy_spec -#define ip6t_policy_addr xt_policy_addr -#define ip6t_policy_elem xt_policy_elem -#define ip6t_policy_info xt_policy_info - -#endif /* _IP6T_POLICY_H */ -- cgit v1.2.3-70-g09d2 From 93fe4483e6fd3e71d17cd919de14b3b1f9eb3795 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 6 Aug 2009 18:14:26 +0900 Subject: sound: make OSS device number claiming optional and schedule its removal If any OSS support is enabled, regardless of built-in or module, sound_core claims full OSS major number (that is, the old 0-255 region) to trap open attempts and request sound modules using custom module aliases. This feature is redundant as chrdev already has such mechanism. This preemptive claiming prevents alternative OSS implementation. The custom module aliases are scheduled to be removed and the previous patch made soundcore emit the standard chrdev aliases too to help transition. This patch schedule the feature for removal in a year and makes it optional so that developers and distros can try new things in the meantime without rebuilding the kernel. The pre-claiming can be turned off by using SOUND_OSS_CORE_PRECLAIM and/or kernel parameter soundcore.preclaim_oss. As this allows sound minors to be individually grabbed by other users, this patch updates sound_insert_unit() such that if registering individual device region fails, it tries the next available slot. For details on removal plan, please read the entry added by this patch in feature-removal-schedule.txt . Signed-off-by: Tejun Heo Cc: Alan Cox Signed-off-by: Takashi Iwai --- Documentation/feature-removal-schedule.txt | 24 ++++++++ sound/Kconfig | 28 ++++++++++ sound/sound_core.c | 88 ++++++++++++++++++++++++------ 3 files changed, 122 insertions(+), 18 deletions(-) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 09e031c5588..f0690bbbd73 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -468,3 +468,27 @@ Why: cpu_policy_rwsem has a new cleaner definition making it local to cpufreq core and contained inside cpufreq.c. Other dependent drivers should not use it in order to safely avoid lockdep issues. Who: Venkatesh Pallipadi + +---------------------------- + +What: sound-slot/service-* module aliases and related clutters in + sound/sound_core.c +When: August 2010 +Why: OSS sound_core grabs all legacy minors (0-255) of SOUND_MAJOR + (14) and requests modules using custom sound-slot/service-* + module aliases. The only benefit of doing this is allowing + use of custom module aliases which might as well be considered + a bug at this point. This preemptive claiming prevents + alternative OSS implementations. + + Till the feature is removed, the kernel will be requesting + both sound-slot/service-* and the standard char-major-* module + aliases and allow turning off the pre-claiming selectively via + CONFIG_SOUND_OSS_CORE_PRECLAIM and soundcore.preclaim_oss + kernel parameter. + + After the transition phase is complete, both the custom module + aliases and switches to disable it will go away. This removal + will also allow making ALSA OSS emulation independent of + sound_core. The dependency will be broken then too. +Who: Tejun Heo diff --git a/sound/Kconfig b/sound/Kconfig index 1eceb85287c..439e15c8faa 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -32,6 +32,34 @@ config SOUND_OSS_CORE bool default n +config SOUND_OSS_CORE_PRECLAIM + bool "Preclaim OSS device numbers" + depends on SOUND_OSS_CORE + default y + help + With this option enabled, the kernel will claim all OSS device + numbers if any OSS support (native or emulation) is enabled + whether the respective module is loaded or not and try to load the + appropriate module using sound-slot/service-* and char-major-* + module aliases when one of the device numbers is opened. With + this option disabled, kernel will only claim actually in-use + device numbers and opening a missing device will generate only the + standard char-major-* aliases. + + The only visible difference is use of additional module aliases + and whether OSS sound devices appear multiple times in + /proc/devices. sound-slot/service-* module aliases are scheduled + to be removed (ie. PRECLAIM won't be available) and this option is + to make the transition easier. This option can be overridden + during boot using the kernel parameter soundcore.preclaim_oss. + + Disabling this allows alternative OSS implementations. + + Please read Documentation/feature-removal-schedule.txt for + details. + + If unusre, say Y. + source "sound/oss/dmasound/Kconfig" if !M68K diff --git a/sound/sound_core.c b/sound/sound_core.c index 786067c49b0..bb4b88e606b 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -127,6 +127,46 @@ extern int msnd_classic_init(void); extern int msnd_pinnacle_init(void); #endif +/* + * By default, OSS sound_core claims full legacy minor range (0-255) + * of SOUND_MAJOR to trap open attempts to any sound minor and + * requests modules using custom sound-slot/service-* module aliases. + * The only benefit of doing this is allowing use of custom module + * aliases instead of the standard char-major-* ones. This behavior + * prevents alternative OSS implementation and is scheduled to be + * removed. + * + * CONFIG_SOUND_OSS_CORE_PRECLAIM and soundcore.preclaim_oss kernel + * parameter are added to allow distros and developers to try and + * switch to alternative implementations without needing to rebuild + * the kernel in the meantime. If preclaim_oss is non-zero, the + * kernel will behave the same as before. All SOUND_MAJOR minors are + * preclaimed and the custom module aliases along with standard chrdev + * ones are emitted if a missing device is opened. If preclaim_oss is + * zero, sound_core only grabs what's actually in use and for missing + * devices only the standard chrdev aliases are requested. + * + * All these clutters are scheduled to be removed along with + * sound-slot/service-* module aliases. Please take a look at + * feature-removal-schedule.txt for details. + */ +#ifdef CONFIG_SOUND_OSS_CORE_PRECLAIM +static int preclaim_oss = 1; +#else +static int preclaim_oss = 0; +#endif + +module_param(preclaim_oss, int, 0444); + +static int soundcore_open(struct inode *, struct file *); + +static const struct file_operations soundcore_fops = +{ + /* We must have an owner or the module locking fails */ + .owner = THIS_MODULE, + .open = soundcore_open, +}; + /* * Low level list operator. Scan the ordered list, find a hole and * join into it. Called with the lock asserted @@ -219,8 +259,9 @@ static int sound_insert_unit(struct sound_unit **list, const struct file_operati if (!s) return -ENOMEM; - + spin_lock(&sound_loader_lock); +retry: r = __sound_insert_unit(s, list, fops, index, low, top); spin_unlock(&sound_loader_lock); @@ -231,11 +272,31 @@ static int sound_insert_unit(struct sound_unit **list, const struct file_operati else sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP); + if (!preclaim_oss) { + /* + * Something else might have grabbed the minor. If + * first free slot is requested, rescan with @low set + * to the next unit; otherwise, -EBUSY. + */ + r = __register_chrdev(SOUND_MAJOR, s->unit_minor, 1, s->name, + &soundcore_fops); + if (r < 0) { + spin_lock(&sound_loader_lock); + __sound_remove_unit(list, s->unit_minor); + if (index < 0) { + low = s->unit_minor + SOUND_STEP; + goto retry; + } + spin_unlock(&sound_loader_lock); + return -EBUSY; + } + } + device_create(sound_class, dev, MKDEV(SOUND_MAJOR, s->unit_minor), NULL, s->name+6); - return r; + return s->unit_minor; - fail: +fail: kfree(s); return r; } @@ -254,6 +315,9 @@ static void sound_remove_unit(struct sound_unit **list, int unit) p = __sound_remove_unit(list, unit); spin_unlock(&sound_loader_lock); if (p) { + if (!preclaim_oss) + __unregister_chrdev(SOUND_MAJOR, p->unit_minor, 1, + p->name); device_destroy(sound_class, MKDEV(SOUND_MAJOR, p->unit_minor)); kfree(p); } @@ -491,19 +555,6 @@ void unregister_sound_dsp(int unit) EXPORT_SYMBOL(unregister_sound_dsp); -/* - * Now our file operations - */ - -static int soundcore_open(struct inode *, struct file *); - -static const struct file_operations soundcore_fops= -{ - /* We must have an owner or the module locking fails */ - .owner = THIS_MODULE, - .open = soundcore_open, -}; - static struct sound_unit *__look_for_unit(int chain, int unit) { struct sound_unit *s; @@ -539,7 +590,7 @@ static int soundcore_open(struct inode *inode, struct file *file) s = __look_for_unit(chain, unit); if (s) new_fops = fops_get(s->unit_fops); - if (!new_fops) { + if (preclaim_oss && !new_fops) { spin_unlock(&sound_loader_lock); /* @@ -605,7 +656,8 @@ static void cleanup_oss_soundcore(void) static int __init init_oss_soundcore(void) { - if (register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops)==-1) { + if (preclaim_oss && + register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) == -1) { printk(KERN_ERR "soundcore: sound device already in use.\n"); return -EBUSY; } -- cgit v1.2.3-70-g09d2 From 48a2f112db5349efb2efadbd94b8cc31a9db84e1 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Fri, 7 Aug 2009 02:58:39 +0000 Subject: documentation: fix wrt. headers rename Signed-off-by: Dmitry Eremin-Solenikov Signed-off-by: David S. Miller --- Documentation/networking/ieee802154.txt | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt index 1d4ed66b1b1..1c0c82c8bc7 100644 --- a/Documentation/networking/ieee802154.txt +++ b/Documentation/networking/ieee802154.txt @@ -22,7 +22,7 @@ int sd = socket(PF_IEEE802154, SOCK_DGRAM, 0); ..... The address family, socket addresses etc. are defined in the -include/net/ieee802154/af_ieee802154.h header or in the special header +include/net/af_ieee802154.h header or in the special header in our userspace package (see either linux-zigbee sourceforge download page or git tree at git://linux-zigbee.git.sourceforge.net/gitroot/linux-zigbee). @@ -33,7 +33,7 @@ MLME - MAC Level Management ============================ Most of IEEE 802.15.4 MLME interfaces are directly mapped on netlink commands. -See the include/net/ieee802154/nl802154.h header. Our userspace tools package +See the include/net/nl802154.h header. Our userspace tools package (see above) provides CLI configuration utility for radio interfaces and simple coordinator for IEEE 802.15.4 networks as an example users of MLME protocol. @@ -54,7 +54,7 @@ Those types of devices require different approach to be hooked into Linux kernel HardMAC ======= -See the header include/net/ieee802154/netdevice.h. You have to implement Linux +See the header include/net/ieee802154_netdev.h. You have to implement Linux net_device, with .type = ARPHRD_IEEE802154. Data is exchanged with socket family code via plain sk_buffs. The control block of sk_buffs will contain additional info as described in the struct ieee802154_mac_cb. @@ -72,5 +72,4 @@ SoftMAC We are going to provide intermediate layer implementing IEEE 802.15.4 MAC in software. This is currently WIP. -See header include/net/ieee802154/mac802154.h and several drivers in -drivers/ieee802154/ +See header include/net/mac802154.h and several drivers in drivers/ieee802154/. -- cgit v1.2.3-70-g09d2 From 00ae4064b1445524752575dd84df227c0687c99d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 14 Aug 2009 15:00:49 +0900 Subject: percpu: rename 4k first chunk allocator to page Page size isn't always 4k depending on arch and configuration. Rename 4k first chunk allocator to page. Signed-off-by: Tejun Heo Cc: David Howells --- Documentation/kernel-parameters.txt | 2 +- arch/x86/kernel/setup_percpu.c | 23 ++++++++++++----------- include/linux/percpu.h | 2 +- mm/percpu.c | 25 ++++++++++++++----------- 4 files changed, 28 insertions(+), 24 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 7936b801fe6..12e9eb77ee0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1920,7 +1920,7 @@ and is between 256 and 4096 characters. It is defined in the file See arch/parisc/kernel/pdc_chassis.c percpu_alloc= [X86] Select which percpu first chunk allocator to use. - Allowed values are one of "lpage", "embed" and "4k". + Allowed values are one of "lpage", "embed" and "page". See comments in arch/x86/kernel/setup_percpu.c for details on each allocator. This parameter is primarily for debugging and performance comparison. diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index a26ff61e2fb..1e17711c29d 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c @@ -249,21 +249,22 @@ static ssize_t __init setup_pcpu_embed(size_t static_size, bool chosen) } /* - * 4k allocator + * Page allocator * - * Boring fallback 4k allocator. This allocator puts more pressure on - * PTE TLBs but other than that behaves nicely on both UMA and NUMA. + * Boring fallback 4k page allocator. This allocator puts more + * pressure on PTE TLBs but other than that behaves nicely on both UMA + * and NUMA. */ -static void __init pcpu4k_populate_pte(unsigned long addr) +static void __init pcpup_populate_pte(unsigned long addr) { populate_extra_pte(addr); } -static ssize_t __init setup_pcpu_4k(size_t static_size) +static ssize_t __init setup_pcpu_page(size_t static_size) { - return pcpu_4k_first_chunk(static_size, PERCPU_FIRST_CHUNK_RESERVE, - pcpu_fc_alloc, pcpu_fc_free, - pcpu4k_populate_pte); + return pcpu_page_first_chunk(static_size, PERCPU_FIRST_CHUNK_RESERVE, + pcpu_fc_alloc, pcpu_fc_free, + pcpup_populate_pte); } /* for explicit first chunk allocator selection */ @@ -307,7 +308,7 @@ void __init setup_per_cpu_areas(void) */ ret = -EINVAL; if (strlen(pcpu_chosen_alloc)) { - if (strcmp(pcpu_chosen_alloc, "4k")) { + if (strcmp(pcpu_chosen_alloc, "page")) { if (!strcmp(pcpu_chosen_alloc, "lpage")) ret = setup_pcpu_lpage(static_size, true); else if (!strcmp(pcpu_chosen_alloc, "embed")) @@ -317,7 +318,7 @@ void __init setup_per_cpu_areas(void) "specified\n", pcpu_chosen_alloc); if (ret < 0) pr_warning("PERCPU: %s allocator failed (%zd), " - "falling back to 4k\n", + "falling back to page size\n", pcpu_chosen_alloc, ret); } } else { @@ -326,7 +327,7 @@ void __init setup_per_cpu_areas(void) ret = setup_pcpu_embed(static_size, false); } if (ret < 0) - ret = setup_pcpu_4k(static_size); + ret = setup_pcpu_page(static_size); if (ret < 0) panic("cannot allocate static percpu area (%zu bytes, err=%zd)", static_size, ret); diff --git a/include/linux/percpu.h b/include/linux/percpu.h index e134c822963..7989f61b03f 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -74,7 +74,7 @@ extern ssize_t __init pcpu_embed_first_chunk( size_t static_size, size_t reserved_size, ssize_t dyn_size); -extern ssize_t __init pcpu_4k_first_chunk( +extern ssize_t __init pcpu_page_first_chunk( size_t static_size, size_t reserved_size, pcpu_fc_alloc_fn_t alloc_fn, pcpu_fc_free_fn_t free_fn, diff --git a/mm/percpu.c b/mm/percpu.c index cbddcbdab68..6feac793490 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -1497,15 +1497,15 @@ ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size, } /** - * pcpu_4k_first_chunk - map the first chunk using PAGE_SIZE pages + * pcpu_page_first_chunk - map the first chunk using PAGE_SIZE pages * @static_size: the size of static percpu area in bytes * @reserved_size: the size of reserved percpu area in bytes * @alloc_fn: function to allocate percpu page, always called with PAGE_SIZE * @free_fn: funtion to free percpu page, always called with PAGE_SIZE * @populate_pte_fn: function to populate pte * - * This is a helper to ease setting up embedded first percpu chunk and - * can be called where pcpu_setup_first_chunk() is expected. + * This is a helper to ease setting up page-remapped first percpu + * chunk and can be called where pcpu_setup_first_chunk() is expected. * * This is the basic allocator. Static percpu area is allocated * page-by-page into vmalloc area. @@ -1514,12 +1514,13 @@ ssize_t __init pcpu_embed_first_chunk(size_t static_size, size_t reserved_size, * The determined pcpu_unit_size which can be used to initialize * percpu access on success, -errno on failure. */ -ssize_t __init pcpu_4k_first_chunk(size_t static_size, size_t reserved_size, - pcpu_fc_alloc_fn_t alloc_fn, - pcpu_fc_free_fn_t free_fn, - pcpu_fc_populate_pte_fn_t populate_pte_fn) +ssize_t __init pcpu_page_first_chunk(size_t static_size, size_t reserved_size, + pcpu_fc_alloc_fn_t alloc_fn, + pcpu_fc_free_fn_t free_fn, + pcpu_fc_populate_pte_fn_t populate_pte_fn) { static struct vm_struct vm; + char psize_str[16]; int unit_pages; size_t pages_size; struct page **pages; @@ -1527,6 +1528,8 @@ ssize_t __init pcpu_4k_first_chunk(size_t static_size, size_t reserved_size, int i, j; ssize_t ret; + snprintf(psize_str, sizeof(psize_str), "%luK", PAGE_SIZE >> 10); + unit_pages = PFN_UP(max_t(size_t, static_size + reserved_size, PCPU_MIN_UNIT_SIZE)); @@ -1542,8 +1545,8 @@ ssize_t __init pcpu_4k_first_chunk(size_t static_size, size_t reserved_size, ptr = alloc_fn(cpu, PAGE_SIZE); if (!ptr) { - pr_warning("PERCPU: failed to allocate " - "4k page for cpu%u\n", cpu); + pr_warning("PERCPU: failed to allocate %s page " + "for cpu%u\n", psize_str, cpu); goto enomem; } pages[j++] = virt_to_page(ptr); @@ -1580,8 +1583,8 @@ ssize_t __init pcpu_4k_first_chunk(size_t static_size, size_t reserved_size, } /* we're ready, commit */ - pr_info("PERCPU: %d 4k pages/cpu @%p s%zu r%zu\n", - unit_pages, vm.addr, static_size, reserved_size); + pr_info("PERCPU: %d %s pages/cpu @%p s%zu r%zu\n", + unit_pages, psize_str, vm.addr, static_size, reserved_size); ret = pcpu_setup_first_chunk(static_size, reserved_size, -1, unit_pages << PAGE_SHIFT, vm.addr, NULL); -- cgit v1.2.3-70-g09d2 From f58dc01ba2ca9fe3ab2ba4ca43d9c8a735cf62d8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 14 Aug 2009 15:00:50 +0900 Subject: percpu: generalize first chunk allocator selection Now that all first chunk allocators are in mm/percpu.c, it makes sense to make generalize percpu_alloc kernel parameter. Define PCPU_FC_* and set pcpu_chosen_fc using early_param() in mm/percpu.c. Arch code can use the set value to determine which first chunk allocator to use. Signed-off-by: Tejun Heo --- Documentation/kernel-parameters.txt | 11 ++++++----- arch/x86/kernel/setup_percpu.c | 24 ++++++------------------ include/linux/percpu.h | 12 ++++++++++++ mm/percpu.c | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 23 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 12e9eb77ee0..dee9ce2e6cf 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1919,11 +1919,12 @@ and is between 256 and 4096 characters. It is defined in the file Format: { 0 | 1 } See arch/parisc/kernel/pdc_chassis.c - percpu_alloc= [X86] Select which percpu first chunk allocator to use. - Allowed values are one of "lpage", "embed" and "page". - See comments in arch/x86/kernel/setup_percpu.c for - details on each allocator. This parameter is primarily - for debugging and performance comparison. + percpu_alloc= Select which percpu first chunk allocator to use. + Currently supported values are "embed", "page" and + "lpage". Archs may support subset or none of the + selections. See comments in mm/percpu.c for details + on each allocator. This parameter is primarily for + debugging and performance comparison. pf. [PARIDE] See Documentation/blockdev/paride.txt. diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index 1e17711c29d..b961d99e641 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c @@ -267,16 +267,6 @@ static ssize_t __init setup_pcpu_page(size_t static_size) pcpup_populate_pte); } -/* for explicit first chunk allocator selection */ -static char pcpu_chosen_alloc[16] __initdata; - -static int __init percpu_alloc_setup(char *str) -{ - strncpy(pcpu_chosen_alloc, str, sizeof(pcpu_chosen_alloc) - 1); - return 0; -} -early_param("percpu_alloc", percpu_alloc_setup); - static inline void setup_percpu_segment(int cpu) { #ifdef CONFIG_X86_32 @@ -307,19 +297,17 @@ void __init setup_per_cpu_areas(void) * each allocator for details. */ ret = -EINVAL; - if (strlen(pcpu_chosen_alloc)) { - if (strcmp(pcpu_chosen_alloc, "page")) { - if (!strcmp(pcpu_chosen_alloc, "lpage")) + if (pcpu_chosen_fc != PCPU_FC_AUTO) { + if (pcpu_chosen_fc != PCPU_FC_PAGE) { + if (pcpu_chosen_fc == PCPU_FC_LPAGE) ret = setup_pcpu_lpage(static_size, true); - else if (!strcmp(pcpu_chosen_alloc, "embed")) - ret = setup_pcpu_embed(static_size, true); else - pr_warning("PERCPU: unknown allocator %s " - "specified\n", pcpu_chosen_alloc); + ret = setup_pcpu_embed(static_size, true); + if (ret < 0) pr_warning("PERCPU: %s allocator failed (%zd), " "falling back to page size\n", - pcpu_chosen_alloc, ret); + pcpu_fc_names[pcpu_chosen_fc], ret); } } else { ret = setup_pcpu_lpage(static_size, false); diff --git a/include/linux/percpu.h b/include/linux/percpu.h index e26788e0da4..9be05cbe5ee 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -59,6 +59,18 @@ extern void *pcpu_base_addr; extern const int *pcpu_unit_map; +enum pcpu_fc { + PCPU_FC_AUTO, + PCPU_FC_EMBED, + PCPU_FC_PAGE, + PCPU_FC_LPAGE, + + PCPU_FC_NR, +}; +extern const char *pcpu_fc_names[PCPU_FC_NR]; + +extern enum pcpu_fc pcpu_chosen_fc; + typedef void * (*pcpu_fc_alloc_fn_t)(unsigned int cpu, size_t size); typedef void (*pcpu_fc_free_fn_t)(void *ptr, size_t size); typedef void (*pcpu_fc_populate_pte_fn_t)(unsigned long addr); diff --git a/mm/percpu.c b/mm/percpu.c index 7971997de31..7fb40bb1555 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -1414,6 +1414,38 @@ size_t __init pcpu_setup_first_chunk(size_t static_size, size_t reserved_size, return pcpu_unit_size; } +const char *pcpu_fc_names[PCPU_FC_NR] __initdata = { + [PCPU_FC_AUTO] = "auto", + [PCPU_FC_EMBED] = "embed", + [PCPU_FC_PAGE] = "page", + [PCPU_FC_LPAGE] = "lpage", +}; + +enum pcpu_fc pcpu_chosen_fc __initdata = PCPU_FC_AUTO; + +static int __init percpu_alloc_setup(char *str) +{ + if (0) + /* nada */; +#ifdef CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK + else if (!strcmp(str, "embed")) + pcpu_chosen_fc = PCPU_FC_EMBED; +#endif +#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK + else if (!strcmp(str, "page")) + pcpu_chosen_fc = PCPU_FC_PAGE; +#endif +#ifdef CONFIG_NEED_PER_CPU_LPAGE_FIRST_CHUNK + else if (!strcmp(str, "lpage")) + pcpu_chosen_fc = PCPU_FC_LPAGE; +#endif + else + pr_warning("PERCPU: unknown allocator %s specified\n", str); + + return 0; +} +early_param("percpu_alloc", percpu_alloc_setup); + static inline size_t pcpu_calc_fc_sizes(size_t static_size, size_t reserved_size, ssize_t *dyn_sizep) -- cgit v1.2.3-70-g09d2 From e933a73f48e3b2d40cfa56d81e2646f194b5a66a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 14 Aug 2009 15:00:53 +0900 Subject: percpu: kill lpage first chunk allocator With x86 converted to embedding allocator, lpage doesn't have any user left. Kill it along with cpa handling code. Signed-off-by: Tejun Heo Cc: Jan Beulich --- Documentation/kernel-parameters.txt | 10 +- arch/x86/mm/pageattr.c | 20 +-- include/linux/percpu.h | 16 --- mm/percpu.c | 241 ------------------------------------ 4 files changed, 6 insertions(+), 281 deletions(-) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index dee9ce2e6cf..e710093e3d3 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1920,11 +1920,11 @@ and is between 256 and 4096 characters. It is defined in the file See arch/parisc/kernel/pdc_chassis.c percpu_alloc= Select which percpu first chunk allocator to use. - Currently supported values are "embed", "page" and - "lpage". Archs may support subset or none of the - selections. See comments in mm/percpu.c for details - on each allocator. This parameter is primarily for - debugging and performance comparison. + Currently supported values are "embed" and "page". + Archs may support subset or none of the selections. + See comments in mm/percpu.c for details on each + allocator. This parameter is primarily for debugging + and performance comparison. pf. [PARIDE] See Documentation/blockdev/paride.txt. diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index dce282f6570..f53cfc7f963 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -687,7 +687,7 @@ static int cpa_process_alias(struct cpa_data *cpa) { struct cpa_data alias_cpa; unsigned long laddr = (unsigned long)__va(cpa->pfn << PAGE_SHIFT); - unsigned long vaddr, remapped; + unsigned long vaddr; int ret; if (cpa->pfn >= max_pfn_mapped) @@ -745,24 +745,6 @@ static int cpa_process_alias(struct cpa_data *cpa) } #endif - /* - * If the PMD page was partially used for per-cpu remapping, - * the recycled area needs to be split and modified. Because - * the area is always proper subset of a PMD page - * cpa->numpages is guaranteed to be 1 for these areas, so - * there's no need to loop over and check for further remaps. - */ - remapped = (unsigned long)pcpu_lpage_remapped((void *)laddr); - if (remapped) { - WARN_ON(cpa->numpages > 1); - alias_cpa = *cpa; - alias_cpa.vaddr = &remapped; - alias_cpa.flags &= ~(CPA_PAGES_ARRAY | CPA_ARRAY); - ret = __change_page_attr_set_clr(&alias_cpa, 0); - if (ret) - return ret; - } - return 0; } diff --git a/include/linux/percpu.h b/include/linux/percpu.h index 25359932740..878836ca999 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -82,7 +82,6 @@ enum pcpu_fc { PCPU_FC_AUTO, PCPU_FC_EMBED, PCPU_FC_PAGE, - PCPU_FC_LPAGE, PCPU_FC_NR, }; @@ -95,7 +94,6 @@ typedef void * (*pcpu_fc_alloc_fn_t)(unsigned int cpu, size_t size, typedef void (*pcpu_fc_free_fn_t)(void *ptr, size_t size); typedef void (*pcpu_fc_populate_pte_fn_t)(unsigned long addr); typedef int (pcpu_fc_cpu_distance_fn_t)(unsigned int from, unsigned int to); -typedef void (*pcpu_fc_map_fn_t)(void *ptr, size_t size, void *addr); extern struct pcpu_alloc_info * __init pcpu_alloc_alloc_info(int nr_groups, int nr_units); @@ -124,20 +122,6 @@ extern int __init pcpu_page_first_chunk(size_t reserved_size, pcpu_fc_populate_pte_fn_t populate_pte_fn); #endif -#ifdef CONFIG_NEED_PER_CPU_LPAGE_FIRST_CHUNK -extern int __init pcpu_lpage_first_chunk(const struct pcpu_alloc_info *ai, - pcpu_fc_alloc_fn_t alloc_fn, - pcpu_fc_free_fn_t free_fn, - pcpu_fc_map_fn_t map_fn); - -extern void *pcpu_lpage_remapped(void *kaddr); -#else -static inline void *pcpu_lpage_remapped(void *kaddr) -{ - return NULL; -} -#endif - /* * Use this to get to a cpu's version of the per-cpu object * dynamically allocated. Non-atomic access to the current CPU's diff --git a/mm/percpu.c b/mm/percpu.c index c2826d05505..77933928107 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -1713,7 +1713,6 @@ const char *pcpu_fc_names[PCPU_FC_NR] __initdata = { [PCPU_FC_AUTO] = "auto", [PCPU_FC_EMBED] = "embed", [PCPU_FC_PAGE] = "page", - [PCPU_FC_LPAGE] = "lpage", }; enum pcpu_fc pcpu_chosen_fc __initdata = PCPU_FC_AUTO; @@ -1729,10 +1728,6 @@ static int __init percpu_alloc_setup(char *str) #ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK else if (!strcmp(str, "page")) pcpu_chosen_fc = PCPU_FC_PAGE; -#endif -#ifdef CONFIG_NEED_PER_CPU_LPAGE_FIRST_CHUNK - else if (!strcmp(str, "lpage")) - pcpu_chosen_fc = PCPU_FC_LPAGE; #endif else pr_warning("PERCPU: unknown allocator %s specified\n", str); @@ -1970,242 +1965,6 @@ out_free_ar: } #endif /* CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK */ -#ifdef CONFIG_NEED_PER_CPU_LPAGE_FIRST_CHUNK -struct pcpul_ent { - void *ptr; - void *map_addr; -}; - -static size_t pcpul_size; -static size_t pcpul_lpage_size; -static int pcpul_nr_lpages; -static struct pcpul_ent *pcpul_map; - -static bool __init pcpul_unit_to_cpu(int unit, const struct pcpu_alloc_info *ai, - unsigned int *cpup) -{ - int group, cunit; - - for (group = 0, cunit = 0; group < ai->nr_groups; group++) { - const struct pcpu_group_info *gi = &ai->groups[group]; - - if (unit < cunit + gi->nr_units) { - if (cpup) - *cpup = gi->cpu_map[unit - cunit]; - return true; - } - cunit += gi->nr_units; - } - - return false; -} - -static int __init pcpul_cpu_to_unit(int cpu, const struct pcpu_alloc_info *ai) -{ - int group, unit, i; - - for (group = 0, unit = 0; group < ai->nr_groups; group++, unit += i) { - const struct pcpu_group_info *gi = &ai->groups[group]; - - for (i = 0; i < gi->nr_units; i++) - if (gi->cpu_map[i] == cpu) - return unit + i; - } - BUG(); -} - -/** - * pcpu_lpage_first_chunk - remap the first percpu chunk using large page - * @ai: pcpu_alloc_info - * @alloc_fn: function to allocate percpu lpage, always called with lpage_size - * @free_fn: function to free percpu memory, @size <= lpage_size - * @map_fn: function to map percpu lpage, always called with lpage_size - * - * This allocator uses large page to build and map the first chunk. - * Unlike other helpers, the caller should provide fully initialized - * @ai. This can be done using pcpu_build_alloc_info(). This two - * stage initialization is to allow arch code to evaluate the - * parameters before committing to it. - * - * Large pages are allocated as directed by @unit_map and other - * parameters and mapped to vmalloc space. Unused holes are returned - * to the page allocator. Note that these holes end up being actively - * mapped twice - once to the physical mapping and to the vmalloc area - * for the first percpu chunk. Depending on architecture, this might - * cause problem when changing page attributes of the returned area. - * These double mapped areas can be detected using - * pcpu_lpage_remapped(). - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int __init pcpu_lpage_first_chunk(const struct pcpu_alloc_info *ai, - pcpu_fc_alloc_fn_t alloc_fn, - pcpu_fc_free_fn_t free_fn, - pcpu_fc_map_fn_t map_fn) -{ - static struct vm_struct vm; - const size_t lpage_size = ai->atom_size; - size_t chunk_size, map_size; - unsigned int cpu; - int i, j, unit, nr_units, rc; - - nr_units = 0; - for (i = 0; i < ai->nr_groups; i++) - nr_units += ai->groups[i].nr_units; - - chunk_size = ai->unit_size * nr_units; - BUG_ON(chunk_size % lpage_size); - - pcpul_size = ai->static_size + ai->reserved_size + ai->dyn_size; - pcpul_lpage_size = lpage_size; - pcpul_nr_lpages = chunk_size / lpage_size; - - /* allocate pointer array and alloc large pages */ - map_size = pcpul_nr_lpages * sizeof(pcpul_map[0]); - pcpul_map = alloc_bootmem(map_size); - - /* allocate all pages */ - for (i = 0; i < pcpul_nr_lpages; i++) { - size_t offset = i * lpage_size; - int first_unit = offset / ai->unit_size; - int last_unit = (offset + lpage_size - 1) / ai->unit_size; - void *ptr; - - /* find out which cpu is mapped to this unit */ - for (unit = first_unit; unit <= last_unit; unit++) - if (pcpul_unit_to_cpu(unit, ai, &cpu)) - goto found; - continue; - found: - ptr = alloc_fn(cpu, lpage_size, lpage_size); - if (!ptr) { - pr_warning("PERCPU: failed to allocate large page " - "for cpu%u\n", cpu); - goto enomem; - } - - pcpul_map[i].ptr = ptr; - } - - /* return unused holes */ - for (unit = 0; unit < nr_units; unit++) { - size_t start = unit * ai->unit_size; - size_t end = start + ai->unit_size; - size_t off, next; - - /* don't free used part of occupied unit */ - if (pcpul_unit_to_cpu(unit, ai, NULL)) - start += pcpul_size; - - /* unit can span more than one page, punch the holes */ - for (off = start; off < end; off = next) { - void *ptr = pcpul_map[off / lpage_size].ptr; - next = min(roundup(off + 1, lpage_size), end); - if (ptr) - free_fn(ptr + off % lpage_size, next - off); - } - } - - /* allocate address, map and copy */ - vm.flags = VM_ALLOC; - vm.size = chunk_size; - vm_area_register_early(&vm, ai->unit_size); - - for (i = 0; i < pcpul_nr_lpages; i++) { - if (!pcpul_map[i].ptr) - continue; - pcpul_map[i].map_addr = vm.addr + i * lpage_size; - map_fn(pcpul_map[i].ptr, lpage_size, pcpul_map[i].map_addr); - } - - for_each_possible_cpu(cpu) - memcpy(vm.addr + pcpul_cpu_to_unit(cpu, ai) * ai->unit_size, - __per_cpu_load, ai->static_size); - - /* we're ready, commit */ - pr_info("PERCPU: large pages @%p s%zu r%zu d%zu u%zu\n", - vm.addr, ai->static_size, ai->reserved_size, ai->dyn_size, - ai->unit_size); - - rc = pcpu_setup_first_chunk(ai, vm.addr); - - /* - * Sort pcpul_map array for pcpu_lpage_remapped(). Unmapped - * lpages are pushed to the end and trimmed. - */ - for (i = 0; i < pcpul_nr_lpages - 1; i++) - for (j = i + 1; j < pcpul_nr_lpages; j++) { - struct pcpul_ent tmp; - - if (!pcpul_map[j].ptr) - continue; - if (pcpul_map[i].ptr && - pcpul_map[i].ptr < pcpul_map[j].ptr) - continue; - - tmp = pcpul_map[i]; - pcpul_map[i] = pcpul_map[j]; - pcpul_map[j] = tmp; - } - - while (pcpul_nr_lpages && !pcpul_map[pcpul_nr_lpages - 1].ptr) - pcpul_nr_lpages--; - - return rc; - -enomem: - for (i = 0; i < pcpul_nr_lpages; i++) - if (pcpul_map[i].ptr) - free_fn(pcpul_map[i].ptr, lpage_size); - free_bootmem(__pa(pcpul_map), map_size); - return -ENOMEM; -} - -/** - * pcpu_lpage_remapped - determine whether a kaddr is in pcpul recycled area - * @kaddr: the kernel address in question - * - * Determine whether @kaddr falls in the pcpul recycled area. This is - * used by pageattr to detect VM aliases and break up the pcpu large - * page mapping such that the same physical page is not mapped under - * different attributes. - * - * The recycled area is always at the tail of a partially used large - * page. - * - * RETURNS: - * Address of corresponding remapped pcpu address if match is found; - * otherwise, NULL. - */ -void *pcpu_lpage_remapped(void *kaddr) -{ - unsigned long lpage_mask = pcpul_lpage_size - 1; - void *lpage_addr = (void *)((unsigned long)kaddr & ~lpage_mask); - unsigned long offset = (unsigned long)kaddr & lpage_mask; - int left = 0, right = pcpul_nr_lpages - 1; - int pos; - - /* pcpul in use at all? */ - if (!pcpul_map) - return NULL; - - /* okay, perform binary search */ - while (left <= right) { - pos = (left + right) / 2; - - if (pcpul_map[pos].ptr < lpage_addr) - left = pos + 1; - else if (pcpul_map[pos].ptr > lpage_addr) - right = pos - 1; - else - return pcpul_map[pos].map_addr + offset; - } - - return NULL; -} -#endif /* CONFIG_NEED_PER_CPU_LPAGE_FIRST_CHUNK */ - /* * Generic percpu area setup. * -- cgit v1.2.3-70-g09d2 From 0aa87445842036f88b53db7f377ad8376bd94ab8 Mon Sep 17 00:00:00 2001 From: Steven Whitehouse Date: Fri, 14 Aug 2009 15:24:46 +0100 Subject: GFS2: Add a document explaining GFS2's uevents This will be essential reading for anybody who wants to understand how GFS2 interacts with the userland gfs_controld, and the details of recovery. Signed-off-by: Steven Whitehouse Signed-off-by: Bob Peterson --- Documentation/filesystems/gfs2-uevents.txt | 100 +++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 Documentation/filesystems/gfs2-uevents.txt (limited to 'Documentation') diff --git a/Documentation/filesystems/gfs2-uevents.txt b/Documentation/filesystems/gfs2-uevents.txt new file mode 100644 index 00000000000..fd966dc9979 --- /dev/null +++ b/Documentation/filesystems/gfs2-uevents.txt @@ -0,0 +1,100 @@ + uevents and GFS2 + ================== + +During the lifetime of a GFS2 mount, a number of uevents are generated. +This document explains what the events are and what they are used +for (by gfs_controld in gfs2-utils). + +A list of GFS2 uevents +----------------------- + +1. ADD + +The ADD event occurs at mount time. It will always be the first +uevent generated by the newly created filesystem. If the mount +is successful, an ONLINE uevent will follow. If it is not successful +then a REMOVE uevent will follow. + +The ADD uevent has two environment variables: SPECTATOR=[0|1] +and RDONLY=[0|1] that specify the spectator status (a read-only mount +with no journal assigned), and read-only (with journal assigned) status +of the filesystem respectively. + +2. ONLINE + +The ONLINE uevent is generated after a successful mount or remount. It +has the same environment variables as the ADD uevent. The ONLINE +uevent, along with the two environment variables for spectator and +RDONLY are a relatively recent addition (2.6.32-rc+) and will not +be generated by older kernels. + +3. CHANGE + +The CHANGE uevent is used in two places. One is when reporting the +successful mount of the filesystem by the first node (FIRSTMOUNT=Done). +This is used as a signal by gfs_controld that it is then ok for other +nodes in the cluster to mount the filesystem. + +The other CHANGE uevent is used to inform of the completion +of journal recovery for one of the filesystems journals. It has +two environment variables, JID= which specifies the journal id which +has just been recovered, and RECOVERY=[Done|Failed] to indicate the +success (or otherwise) of the operation. These uevents are generated +for every journal recovered, whether it is during the initial mount +process or as the result of gfs_controld requesting a specific journal +recovery via the /sys/fs/gfs2//lock_module/recovery file. + +Because the CHANGE uevent was used (in early versions of gfs_controld) +without checking the environment variables to discover the state, we +cannot add any more functions to it without running the risk of +someone using an older version of the user tools and breaking their +cluster. For this reason the ONLINE uevent was used when adding a new +uevent for a successful mount or remount. + +4. OFFLINE + +The OFFLINE uevent is only generated due to filesystem errors and is used +as part of the "withdraw" mechanism. Currently this doesn't give any +information about what the error is, which is something that needs to +be fixed. + +5. REMOVE + +The REMOVE uevent is generated at the end of an unsuccessful mount +or at the end of a umount of the filesystem. All REMOVE uevents will +have been preceeded by at least an ADD uevent for the same fileystem, +and unlike the other uevents is generated automatically by the kernel's +kobject subsystem. + + +Information common to all GFS2 uevents (uevent environment variables) +---------------------------------------------------------------------- + +1. LOCKTABLE= + +The LOCKTABLE is a string, as supplied on the mount command +line (locktable=) or via fstab. It is used as a filesystem label +as well as providing the information for a lock_dlm mount to be +able to join the cluster. + +2. LOCKPROTO= + +The LOCKPROTO is a string, and its value depends on what is set +on the mount command line, or via fstab. It will be either +lock_nolock or lock_dlm. In the future other lock managers +may be supported. + +3. JOURNALID= + +If a journal is in use by the filesystem (journals are not +assigned for spectator mounts) then this will give the +numeric journal id in all GFS2 uevents. + +4. UUID= + +With recent versions of gfs2-utils, mkfs.gfs2 writes a UUID +into the filesystem superblock. If it exists, this will +be included in every uevent relating to the filesystem. + + + -- cgit v1.2.3-70-g09d2 From a0aea57786fe9c6b62b1a4f28409582520fa494f Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Wed, 19 Aug 2009 18:53:39 +0400 Subject: ieee802154: document the skb->cb usage clearly. Signed-off-by: Dmitry Eremin-Solenikov --- Documentation/networking/ieee802154.txt | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ieee802154.txt b/Documentation/networking/ieee802154.txt index 1c0c82c8bc7..23c995e6403 100644 --- a/Documentation/networking/ieee802154.txt +++ b/Documentation/networking/ieee802154.txt @@ -56,8 +56,12 @@ HardMAC See the header include/net/ieee802154_netdev.h. You have to implement Linux net_device, with .type = ARPHRD_IEEE802154. Data is exchanged with socket family -code via plain sk_buffs. The control block of sk_buffs will contain additional -info as described in the struct ieee802154_mac_cb. +code via plain sk_buffs. On skb reception skb->cb must contain additional +info as described in the struct ieee802154_mac_cb. During packet transmission +the skb->cb is used to provide additional data to device's header_ops->create +function. Be aware, that this data can be overriden later (when socket code +submits skb to qdisc), so if you need something from that cb later, you should +store info in the skb->data on your own. To hook the MLME interface you have to populate the ml_priv field of your net_device with a pointer to struct ieee802154_mlme_ops instance. All fields are @@ -73,3 +77,4 @@ We are going to provide intermediate layer implementing IEEE 802.15.4 MAC in software. This is currently WIP. See header include/net/mac802154.h and several drivers in drivers/ieee802154/. + -- cgit v1.2.3-70-g09d2 From e571cbf1a4f8d8b6cfd4898df718dae84c75a8e1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 19 Aug 2009 18:12:27 -0400 Subject: NFS: Add a dns resolver for use with NFSv4 referrals and migration The NFSv4 and NFSv4.1 protocols both allow for the redirection of a client from one server to another in order to support filesystem migration and replication. For full protocol support, we need to add the ability to convert a DNS host name into an IP address that we can feed to the RPC client. We'll reuse the sunrpc cache, now that it has been converted to work with rpc_pipefs. Signed-off-by: Trond Myklebust --- Documentation/filesystems/nfs.txt | 98 +++++++++++ Documentation/kernel-parameters.txt | 8 + fs/nfs/Makefile | 3 +- fs/nfs/cache_lib.c | 140 +++++++++++++++ fs/nfs/cache_lib.h | 27 +++ fs/nfs/dns_resolve.c | 335 ++++++++++++++++++++++++++++++++++++ fs/nfs/dns_resolve.h | 14 ++ fs/nfs/inode.c | 8 + net/sunrpc/rpc_pipe.c | 7 + 9 files changed, 639 insertions(+), 1 deletion(-) create mode 100644 Documentation/filesystems/nfs.txt create mode 100644 fs/nfs/cache_lib.c create mode 100644 fs/nfs/cache_lib.h create mode 100644 fs/nfs/dns_resolve.c create mode 100644 fs/nfs/dns_resolve.h (limited to 'Documentation') diff --git a/Documentation/filesystems/nfs.txt b/Documentation/filesystems/nfs.txt new file mode 100644 index 00000000000..f50f26ce6cd --- /dev/null +++ b/Documentation/filesystems/nfs.txt @@ -0,0 +1,98 @@ + +The NFS client +============== + +The NFS version 2 protocol was first documented in RFC1094 (March 1989). +Since then two more major releases of NFS have been published, with NFSv3 +being documented in RFC1813 (June 1995), and NFSv4 in RFC3530 (April +2003). + +The Linux NFS client currently supports all the above published versions, +and work is in progress on adding support for minor version 1 of the NFSv4 +protocol. + +The purpose of this document is to provide information on some of the +upcall interfaces that are used in order to provide the NFS client with +some of the information that it requires in order to fully comply with +the NFS spec. + +The DNS resolver +================ + +NFSv4 allows for one server to refer the NFS client to data that has been +migrated onto another server by means of the special "fs_locations" +attribute. See + http://tools.ietf.org/html/rfc3530#section-6 +and + http://tools.ietf.org/html/draft-ietf-nfsv4-referrals-00 + +The fs_locations information can take the form of either an ip address and +a path, or a DNS hostname and a path. The latter requires the NFS client to +do a DNS lookup in order to mount the new volume, and hence the need for an +upcall to allow userland to provide this service. + +Assuming that the user has the 'rpc_pipefs' filesystem mounted in the usual +/var/lib/nfs/rpc_pipefs, the upcall consists of the following steps: + + (1) The process checks the dns_resolve cache to see if it contains a + valid entry. If so, it returns that entry and exits. + + (2) If no valid entry exists, the helper script '/sbin/nfs_cache_getent' + (may be changed using the 'nfs.cache_getent' kernel boot parameter) + is run, with two arguments: + - the cache name, "dns_resolve" + - the hostname to resolve + + (3) After looking up the corresponding ip address, the helper script + writes the result into the rpc_pipefs pseudo-file + '/var/lib/nfs/rpc_pipefs/cache/dns_resolve/channel' + in the following (text) format: + + " \n" + + Where is in the usual IPv4 (123.456.78.90) or IPv6 + (ffee:ddcc:bbaa:9988:7766:5544:3322:1100, ffee::1100, ...) format. + is identical to the second argument of the helper + script, and is the 'time to live' of this cache entry (in + units of seconds). + + Note: If is invalid, say the string "0", then a negative + entry is created, which will cause the kernel to treat the hostname + as having no valid DNS translation. + + + + +A basic sample /sbin/nfs_cache_getent +===================================== + +#!/bin/bash +# +ttl=600 +# +cut=/usr/bin/cut +getent=/usr/bin/getent +rpc_pipefs=/var/lib/nfs/rpc_pipefs +# +die() +{ + echo "Usage: $0 cache_name entry_name" + exit 1 +} + +[ $# -lt 2 ] && die +cachename="$1" +cache_path=${rpc_pipefs}/cache/${cachename}/channel + +case "${cachename}" in + dns_resolve) + name="$2" + result="$(${getent} hosts ${name} | ${cut} -f1 -d\ )" + [ -z "${result}" ] && result="0" + ;; + *) + die + ;; +esac +echo "${result} ${name} ${ttl}" >${cache_path} + diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index c08813dbfce..ce885375581 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1503,6 +1503,14 @@ and is between 256 and 4096 characters. It is defined in the file [NFS] set the TCP port on which the NFSv4 callback channel should listen. + nfs.cache_getent= + [NFS] sets the pathname to the program which is used + to update the NFS client cache entries. + + nfs.cache_getent_timeout= + [NFS] sets the timeout after which an attempt to + update a cache entry is deemed to have failed. + nfs.idmap_cache_timeout= [NFS] set the maximum lifetime for idmapper cache entries. diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile index 845159814de..da7fda639ea 100644 --- a/fs/nfs/Makefile +++ b/fs/nfs/Makefile @@ -6,7 +6,8 @@ obj-$(CONFIG_NFS_FS) += nfs.o nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \ direct.o pagelist.o proc.o read.o symlink.o unlink.o \ - write.o namespace.o mount_clnt.o + write.o namespace.o mount_clnt.o \ + dns_resolve.o cache_lib.o nfs-$(CONFIG_ROOT_NFS) += nfsroot.o nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o nfs-$(CONFIG_NFS_V3_ACL) += nfs3acl.o diff --git a/fs/nfs/cache_lib.c b/fs/nfs/cache_lib.c new file mode 100644 index 00000000000..b4ffd0146ea --- /dev/null +++ b/fs/nfs/cache_lib.c @@ -0,0 +1,140 @@ +/* + * linux/fs/nfs/cache_lib.c + * + * Helper routines for the NFS client caches + * + * Copyright (c) 2009 Trond Myklebust + */ +#include +#include +#include +#include +#include +#include +#include + +#include "cache_lib.h" + +#define NFS_CACHE_UPCALL_PATHLEN 256 +#define NFS_CACHE_UPCALL_TIMEOUT 15 + +static char nfs_cache_getent_prog[NFS_CACHE_UPCALL_PATHLEN] = + "/sbin/nfs_cache_getent"; +static unsigned long nfs_cache_getent_timeout = NFS_CACHE_UPCALL_TIMEOUT; + +module_param_string(cache_getent, nfs_cache_getent_prog, + sizeof(nfs_cache_getent_prog), 0600); +MODULE_PARM_DESC(cache_getent, "Path to the client cache upcall program"); +module_param_named(cache_getent_timeout, nfs_cache_getent_timeout, ulong, 0600); +MODULE_PARM_DESC(cache_getent_timeout, "Timeout (in seconds) after which " + "the cache upcall is assumed to have failed"); + +int nfs_cache_upcall(struct cache_detail *cd, char *entry_name) +{ + static char *envp[] = { "HOME=/", + "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + NULL + }; + char *argv[] = { + nfs_cache_getent_prog, + cd->name, + entry_name, + NULL + }; + int ret = -EACCES; + + if (nfs_cache_getent_prog[0] == '\0') + goto out; + ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); + /* + * Disable the upcall mechanism if we're getting an ENOENT or + * EACCES error. The admin can re-enable it on the fly by using + * sysfs to set the 'cache_getent' parameter once the problem + * has been fixed. + */ + if (ret == -ENOENT || ret == -EACCES) + nfs_cache_getent_prog[0] = '\0'; +out: + return ret > 0 ? 0 : ret; +} + +/* + * Deferred request handling + */ +void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq) +{ + if (atomic_dec_and_test(&dreq->count)) + kfree(dreq); +} + +static void nfs_dns_cache_revisit(struct cache_deferred_req *d, int toomany) +{ + struct nfs_cache_defer_req *dreq; + + dreq = container_of(d, struct nfs_cache_defer_req, deferred_req); + + complete_all(&dreq->completion); + nfs_cache_defer_req_put(dreq); +} + +static struct cache_deferred_req *nfs_dns_cache_defer(struct cache_req *req) +{ + struct nfs_cache_defer_req *dreq; + + dreq = container_of(req, struct nfs_cache_defer_req, req); + dreq->deferred_req.revisit = nfs_dns_cache_revisit; + atomic_inc(&dreq->count); + + return &dreq->deferred_req; +} + +struct nfs_cache_defer_req *nfs_cache_defer_req_alloc(void) +{ + struct nfs_cache_defer_req *dreq; + + dreq = kzalloc(sizeof(*dreq), GFP_KERNEL); + if (dreq) { + init_completion(&dreq->completion); + atomic_set(&dreq->count, 1); + dreq->req.defer = nfs_dns_cache_defer; + } + return dreq; +} + +int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq) +{ + if (wait_for_completion_timeout(&dreq->completion, + nfs_cache_getent_timeout * HZ) == 0) + return -ETIMEDOUT; + return 0; +} + +int nfs_cache_register(struct cache_detail *cd) +{ + struct nameidata nd; + struct vfsmount *mnt; + int ret; + + mnt = rpc_get_mount(); + if (IS_ERR(mnt)) + return PTR_ERR(mnt); + ret = vfs_path_lookup(mnt->mnt_root, mnt, "/cache", 0, &nd); + if (ret) + goto err; + ret = sunrpc_cache_register_pipefs(nd.path.dentry, + cd->name, 0600, cd); + path_put(&nd.path); + if (!ret) + return ret; +err: + rpc_put_mount(); + return ret; +} + +void nfs_cache_unregister(struct cache_detail *cd) +{ + sunrpc_cache_unregister_pipefs(cd); + rpc_put_mount(); +} + diff --git a/fs/nfs/cache_lib.h b/fs/nfs/cache_lib.h new file mode 100644 index 00000000000..76f856e284e --- /dev/null +++ b/fs/nfs/cache_lib.h @@ -0,0 +1,27 @@ +/* + * Helper routines for the NFS client caches + * + * Copyright (c) 2009 Trond Myklebust + */ + +#include +#include +#include + +/* + * Deferred request handling + */ +struct nfs_cache_defer_req { + struct cache_req req; + struct cache_deferred_req deferred_req; + struct completion completion; + atomic_t count; +}; + +extern int nfs_cache_upcall(struct cache_detail *cd, char *entry_name); +extern struct nfs_cache_defer_req *nfs_cache_defer_req_alloc(void); +extern void nfs_cache_defer_req_put(struct nfs_cache_defer_req *dreq); +extern int nfs_cache_wait_for_upcall(struct nfs_cache_defer_req *dreq); + +extern int nfs_cache_register(struct cache_detail *cd); +extern void nfs_cache_unregister(struct cache_detail *cd); diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c new file mode 100644 index 00000000000..f4d54ba97cc --- /dev/null +++ b/fs/nfs/dns_resolve.c @@ -0,0 +1,335 @@ +/* + * linux/fs/nfs/dns_resolve.c + * + * Copyright (c) 2009 Trond Myklebust + * + * Resolves DNS hostnames into valid ip addresses + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dns_resolve.h" +#include "cache_lib.h" + +#define NFS_DNS_HASHBITS 4 +#define NFS_DNS_HASHTBL_SIZE (1 << NFS_DNS_HASHBITS) + +static struct cache_head *nfs_dns_table[NFS_DNS_HASHTBL_SIZE]; + +struct nfs_dns_ent { + struct cache_head h; + + char *hostname; + size_t namelen; + + struct sockaddr_storage addr; + size_t addrlen; +}; + + +static void nfs_dns_ent_init(struct cache_head *cnew, + struct cache_head *ckey) +{ + struct nfs_dns_ent *new; + struct nfs_dns_ent *key; + + new = container_of(cnew, struct nfs_dns_ent, h); + key = container_of(ckey, struct nfs_dns_ent, h); + + kfree(new->hostname); + new->hostname = kstrndup(key->hostname, key->namelen, GFP_KERNEL); + if (new->hostname) { + new->namelen = key->namelen; + memcpy(&new->addr, &key->addr, key->addrlen); + new->addrlen = key->addrlen; + } else { + new->namelen = 0; + new->addrlen = 0; + } +} + +static void nfs_dns_ent_put(struct kref *ref) +{ + struct nfs_dns_ent *item; + + item = container_of(ref, struct nfs_dns_ent, h.ref); + kfree(item->hostname); + kfree(item); +} + +static struct cache_head *nfs_dns_ent_alloc(void) +{ + struct nfs_dns_ent *item = kmalloc(sizeof(*item), GFP_KERNEL); + + if (item != NULL) { + item->hostname = NULL; + item->namelen = 0; + item->addrlen = 0; + return &item->h; + } + return NULL; +}; + +static unsigned int nfs_dns_hash(const struct nfs_dns_ent *key) +{ + return hash_str(key->hostname, NFS_DNS_HASHBITS); +} + +static void nfs_dns_request(struct cache_detail *cd, + struct cache_head *ch, + char **bpp, int *blen) +{ + struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); + + qword_add(bpp, blen, key->hostname); + (*bpp)[-1] = '\n'; +} + +static int nfs_dns_upcall(struct cache_detail *cd, + struct cache_head *ch) +{ + struct nfs_dns_ent *key = container_of(ch, struct nfs_dns_ent, h); + int ret; + + ret = nfs_cache_upcall(cd, key->hostname); + if (ret) + ret = sunrpc_cache_pipe_upcall(cd, ch, nfs_dns_request); + return ret; +} + +static int nfs_dns_match(struct cache_head *ca, + struct cache_head *cb) +{ + struct nfs_dns_ent *a; + struct nfs_dns_ent *b; + + a = container_of(ca, struct nfs_dns_ent, h); + b = container_of(cb, struct nfs_dns_ent, h); + + if (a->namelen == 0 || a->namelen != b->namelen) + return 0; + return memcmp(a->hostname, b->hostname, a->namelen) == 0; +} + +static int nfs_dns_show(struct seq_file *m, struct cache_detail *cd, + struct cache_head *h) +{ + struct nfs_dns_ent *item; + long ttl; + + if (h == NULL) { + seq_puts(m, "# ip address hostname ttl\n"); + return 0; + } + item = container_of(h, struct nfs_dns_ent, h); + ttl = (long)item->h.expiry_time - (long)get_seconds(); + if (ttl < 0) + ttl = 0; + + if (!test_bit(CACHE_NEGATIVE, &h->flags)) { + char buf[INET6_ADDRSTRLEN+IPV6_SCOPE_ID_LEN+1]; + + rpc_ntop((struct sockaddr *)&item->addr, buf, sizeof(buf)); + seq_printf(m, "%15s ", buf); + } else + seq_puts(m, " "); + seq_printf(m, "%15s %ld\n", item->hostname, ttl); + return 0; +} + +struct nfs_dns_ent *nfs_dns_lookup(struct cache_detail *cd, + struct nfs_dns_ent *key) +{ + struct cache_head *ch; + + ch = sunrpc_cache_lookup(cd, + &key->h, + nfs_dns_hash(key)); + if (!ch) + return NULL; + return container_of(ch, struct nfs_dns_ent, h); +} + +struct nfs_dns_ent *nfs_dns_update(struct cache_detail *cd, + struct nfs_dns_ent *new, + struct nfs_dns_ent *key) +{ + struct cache_head *ch; + + ch = sunrpc_cache_update(cd, + &new->h, &key->h, + nfs_dns_hash(key)); + if (!ch) + return NULL; + return container_of(ch, struct nfs_dns_ent, h); +} + +static int nfs_dns_parse(struct cache_detail *cd, char *buf, int buflen) +{ + char buf1[NFS_DNS_HOSTNAME_MAXLEN+1]; + struct nfs_dns_ent key, *item; + unsigned long ttl; + ssize_t len; + int ret = -EINVAL; + + if (buf[buflen-1] != '\n') + goto out; + buf[buflen-1] = '\0'; + + len = qword_get(&buf, buf1, sizeof(buf1)); + if (len <= 0) + goto out; + key.addrlen = rpc_pton(buf1, len, + (struct sockaddr *)&key.addr, + sizeof(key.addr)); + + len = qword_get(&buf, buf1, sizeof(buf1)); + if (len <= 0) + goto out; + + key.hostname = buf1; + key.namelen = len; + memset(&key.h, 0, sizeof(key.h)); + + ttl = get_expiry(&buf); + if (ttl == 0) + goto out; + key.h.expiry_time = ttl + get_seconds(); + + ret = -ENOMEM; + item = nfs_dns_lookup(cd, &key); + if (item == NULL) + goto out; + + if (key.addrlen == 0) + set_bit(CACHE_NEGATIVE, &key.h.flags); + + item = nfs_dns_update(cd, &key, item); + if (item == NULL) + goto out; + + ret = 0; + cache_put(&item->h, cd); +out: + return ret; +} + +static struct cache_detail nfs_dns_resolve = { + .owner = THIS_MODULE, + .hash_size = NFS_DNS_HASHTBL_SIZE, + .hash_table = nfs_dns_table, + .name = "dns_resolve", + .cache_put = nfs_dns_ent_put, + .cache_upcall = nfs_dns_upcall, + .cache_parse = nfs_dns_parse, + .cache_show = nfs_dns_show, + .match = nfs_dns_match, + .init = nfs_dns_ent_init, + .update = nfs_dns_ent_init, + .alloc = nfs_dns_ent_alloc, +}; + +static int do_cache_lookup(struct cache_detail *cd, + struct nfs_dns_ent *key, + struct nfs_dns_ent **item, + struct nfs_cache_defer_req *dreq) +{ + int ret = -ENOMEM; + + *item = nfs_dns_lookup(cd, key); + if (*item) { + ret = cache_check(cd, &(*item)->h, &dreq->req); + if (ret) + *item = NULL; + } + return ret; +} + +static int do_cache_lookup_nowait(struct cache_detail *cd, + struct nfs_dns_ent *key, + struct nfs_dns_ent **item) +{ + int ret = -ENOMEM; + + *item = nfs_dns_lookup(cd, key); + if (!*item) + goto out_err; + ret = -ETIMEDOUT; + if (!test_bit(CACHE_VALID, &(*item)->h.flags) + || (*item)->h.expiry_time < get_seconds() + || cd->flush_time > (*item)->h.last_refresh) + goto out_put; + ret = -ENOENT; + if (test_bit(CACHE_NEGATIVE, &(*item)->h.flags)) + goto out_put; + return 0; +out_put: + cache_put(&(*item)->h, cd); +out_err: + *item = NULL; + return ret; +} + +static int do_cache_lookup_wait(struct cache_detail *cd, + struct nfs_dns_ent *key, + struct nfs_dns_ent **item) +{ + struct nfs_cache_defer_req *dreq; + int ret = -ENOMEM; + + dreq = nfs_cache_defer_req_alloc(); + if (!dreq) + goto out; + ret = do_cache_lookup(cd, key, item, dreq); + if (ret == -EAGAIN) { + ret = nfs_cache_wait_for_upcall(dreq); + if (!ret) + ret = do_cache_lookup_nowait(cd, key, item); + } + nfs_cache_defer_req_put(dreq); +out: + return ret; +} + +ssize_t nfs_dns_resolve_name(char *name, size_t namelen, + struct sockaddr *sa, size_t salen) +{ + struct nfs_dns_ent key = { + .hostname = name, + .namelen = namelen, + }; + struct nfs_dns_ent *item = NULL; + ssize_t ret; + + ret = do_cache_lookup_wait(&nfs_dns_resolve, &key, &item); + if (ret == 0) { + if (salen >= item->addrlen) { + memcpy(sa, &item->addr, item->addrlen); + ret = item->addrlen; + } else + ret = -EOVERFLOW; + cache_put(&item->h, &nfs_dns_resolve); + } else if (ret == -ENOENT) + ret = -ESRCH; + return ret; +} + +int nfs_dns_resolver_init(void) +{ + return nfs_cache_register(&nfs_dns_resolve); +} + +void nfs_dns_resolver_destroy(void) +{ + nfs_cache_unregister(&nfs_dns_resolve); +} + diff --git a/fs/nfs/dns_resolve.h b/fs/nfs/dns_resolve.h new file mode 100644 index 00000000000..a3f0938babf --- /dev/null +++ b/fs/nfs/dns_resolve.h @@ -0,0 +1,14 @@ +/* + * Resolve DNS hostnames into valid ip addresses + */ +#ifndef __LINUX_FS_NFS_DNS_RESOLVE_H +#define __LINUX_FS_NFS_DNS_RESOLVE_H + +#define NFS_DNS_HOSTNAME_MAXLEN (128) + +extern int nfs_dns_resolver_init(void); +extern void nfs_dns_resolver_destroy(void); +extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen, + struct sockaddr *sa, size_t salen); + +#endif diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index fe5a8b45d86..060022b4651 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -46,6 +46,7 @@ #include "iostat.h" #include "internal.h" #include "fscache.h" +#include "dns_resolve.h" #define NFSDBG_FACILITY NFSDBG_VFS @@ -1506,6 +1507,10 @@ static int __init init_nfs_fs(void) { int err; + err = nfs_dns_resolver_init(); + if (err < 0) + goto out8; + err = nfs_fscache_register(); if (err < 0) goto out7; @@ -1564,6 +1569,8 @@ out5: out6: nfs_fscache_unregister(); out7: + nfs_dns_resolver_destroy(); +out8: return err; } @@ -1575,6 +1582,7 @@ static void __exit exit_nfs_fs(void) nfs_destroy_inodecache(); nfs_destroy_nfspagecache(); nfs_fscache_unregister(); + nfs_dns_resolver_destroy(); #ifdef CONFIG_PROC_FS rpc_proc_unregister("nfs"); #endif diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index 3fdacaf5c70..7f676bdf70d 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -416,11 +416,13 @@ struct vfsmount *rpc_get_mount(void) return ERR_PTR(err); return rpc_mount; } +EXPORT_SYMBOL_GPL(rpc_get_mount); void rpc_put_mount(void) { simple_release_fs(&rpc_mount, &rpc_mount_count); } +EXPORT_SYMBOL_GPL(rpc_put_mount); static int rpc_delete_dentry(struct dentry *dentry) { @@ -946,6 +948,7 @@ enum { RPCAUTH_portmap, RPCAUTH_statd, RPCAUTH_nfsd4_cb, + RPCAUTH_cache, RPCAUTH_RootEOF }; @@ -974,6 +977,10 @@ static const struct rpc_filelist files[] = { .name = "nfsd4_cb", .mode = S_IFDIR | S_IRUGO | S_IXUGO, }, + [RPCAUTH_cache] = { + .name = "cache", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, }; static int -- cgit v1.2.3-70-g09d2 From fc69f4a6af49ee69475dc4217924d9edf77760e0 Mon Sep 17 00:00:00 2001 From: Tai-hwa Liang Date: Sun, 10 May 2009 18:15:39 -0700 Subject: Input: add new driver for Sentelic Finger Sensing Pad This is the driver for Sentelic Finger Sensing Pad which can be found on MSI WIND Netbook. Signed-off-by: Tai-hwa Liang Signed-off-by: Dmitry Torokhov --- Documentation/input/sentelic.txt | 475 ++++++++++++++++++++ drivers/input/mouse/Kconfig | 8 + drivers/input/mouse/Makefile | 1 + drivers/input/mouse/psmouse-base.c | 26 +- drivers/input/mouse/psmouse.h | 1 + drivers/input/mouse/sentelic.c | 867 +++++++++++++++++++++++++++++++++++++ drivers/input/mouse/sentelic.h | 98 +++++ drivers/input/serio/libps2.c | 15 +- include/linux/libps2.h | 1 + 9 files changed, 1488 insertions(+), 4 deletions(-) create mode 100644 Documentation/input/sentelic.txt create mode 100644 drivers/input/mouse/sentelic.c create mode 100644 drivers/input/mouse/sentelic.h (limited to 'Documentation') diff --git a/Documentation/input/sentelic.txt b/Documentation/input/sentelic.txt new file mode 100644 index 00000000000..f7160a2fb6a --- /dev/null +++ b/Documentation/input/sentelic.txt @@ -0,0 +1,475 @@ +Copyright (C) 2002-2008 Sentelic Corporation. +Last update: Oct-31-2008 + +============================================================================== +* Finger Sensing Pad Intellimouse Mode(scrolling wheel, 4th and 5th buttons) +============================================================================== +A) MSID 4: Scrolling wheel mode plus Forward page(4th button) and Backward + page (5th button) +@1. Set sample rate to 200; +@2. Set sample rate to 200; +@3. Set sample rate to 80; +@4. Issuing the "Get device ID" command (0xF2) and waits for the response; +@5. FSP will respond 0x04. + +Packet 1 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| + 1 |Y|X|y|x|1|M|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 | | |B|F|W|W|W|W| + |---------------| |---------------| |---------------| |---------------| + +Byte 1: Bit7 => Y overflow + Bit6 => X overflow + Bit5 => Y sign bit + Bit4 => X sign bit + Bit3 => 1 + Bit2 => Middle Button, 1 is pressed, 0 is not pressed. + Bit1 => Right Button, 1 is pressed, 0 is not pressed. + Bit0 => Left Button, 1 is pressed, 0 is not pressed. +Byte 2: X Movement(9-bit 2's complement integers) +Byte 3: Y Movement(9-bit 2's complement integers) +Byte 4: Bit3~Bit0 => the scrolling wheel's movement since the last data report. + valid values, -8 ~ +7 + Bit4 => 1 = 4th mouse button is pressed, Forward one page. + 0 = 4th mouse button is not pressed. + Bit5 => 1 = 5th mouse button is pressed, Backward one page. + 0 = 5th mouse button is not pressed. + +B) MSID 6: Horizontal and Vertical scrolling. +@ Set bit 1 in register 0x40 to 1 + +# FSP replaces scrolling wheel's movement as 4 bits to show horizontal and + vertical scrolling. + +Packet 1 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| + 1 |Y|X|y|x|1|M|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 | | |B|F|l|r|u|d| + |---------------| |---------------| |---------------| |---------------| + +Byte 1: Bit7 => Y overflow + Bit6 => X overflow + Bit5 => Y sign bit + Bit4 => X sign bit + Bit3 => 1 + Bit2 => Middle Button, 1 is pressed, 0 is not pressed. + Bit1 => Right Button, 1 is pressed, 0 is not pressed. + Bit0 => Left Button, 1 is pressed, 0 is not pressed. +Byte 2: X Movement(9-bit 2's complement integers) +Byte 3: Y Movement(9-bit 2's complement integers) +Byte 4: Bit0 => the Vertical scrolling movement downward. + Bit1 => the Vertical scrolling movement upward. + Bit2 => the Vertical scrolling movement rightward. + Bit3 => the Vertical scrolling movement leftward. + Bit4 => 1 = 4th mouse button is pressed, Forward one page. + 0 = 4th mouse button is not pressed. + Bit5 => 1 = 5th mouse button is pressed, Backward one page. + 0 = 5th mouse button is not pressed. + +C) MSID 7: +# FSP uses 2 packets(8 Bytes) data to represent Absolute Position + so we have PACKET NUMBER to identify packets. + If PACKET NUMBER is 0, the packet is Packet 1. + If PACKET NUMBER is 1, the packet is Packet 2. + Please count this number in program. + +# MSID6 special packet will be enable at the same time when enable MSID 7. + +============================================================================== +* Absolute position for STL3886-G0. +============================================================================== +@ Set bit 2 or 3 in register 0x40 to 1 +@ Set bit 6 in register 0x40 to 1 + +Packet 1 (ABSOLUTE POSITION) + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| + 1 |0|1|V|1|1|M|R|L| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |r|l|d|u|X|X|Y|Y| + |---------------| |---------------| |---------------| |---------------| + +Byte 1: Bit7~Bit6 => 00, Normal data packet + => 01, Absolute coordination packet + => 10, Notify packet + Bit5 => valid bit + Bit4 => 1 + Bit3 => 1 + Bit2 => Middle Button, 1 is pressed, 0 is not pressed. + Bit1 => Right Button, 1 is pressed, 0 is not pressed. + Bit0 => Left Button, 1 is pressed, 0 is not pressed. +Byte 2: X coordinate (xpos[9:2]) +Byte 3: Y coordinate (ypos[9:2]) +Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0]) + Bit3~Bit2 => X coordinate (ypos[1:0]) + Bit4 => scroll up + Bit5 => scroll down + Bit6 => scroll left + Bit7 => scroll right + +Notify Packet for G0 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| + 1 |1|0|0|1|1|M|R|L| 2 |C|C|C|C|C|C|C|C| 3 |M|M|M|M|M|M|M|M| 4 |0|0|0|0|0|0|0|0| + |---------------| |---------------| |---------------| |---------------| + +Byte 1: Bit7~Bit6 => 00, Normal data packet + => 01, Absolute coordination packet + => 10, Notify packet + Bit5 => 0 + Bit4 => 1 + Bit3 => 1 + Bit2 => Middle Button, 1 is pressed, 0 is not pressed. + Bit1 => Right Button, 1 is pressed, 0 is not pressed. + Bit0 => Left Button, 1 is pressed, 0 is not pressed. +Byte 2: Message Type => 0x5A (Enable/Disable status packet) + Mode Type => 0xA5 (Normal/Icon mode status) +Byte 3: Message Type => 0x00 (Disabled) + => 0x01 (Enabled) + Mode Type => 0x00 (Normal) + => 0x01 (Icon) +Byte 4: Bit7~Bit0 => Don't Care + +============================================================================== +* Absolute position for STL3888-A0. +============================================================================== +Packet 1 (ABSOLUTE POSITION) + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| + 1 |0|1|V|A|1|L|0|1| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |x|x|y|y|X|X|Y|Y| + |---------------| |---------------| |---------------| |---------------| + +Byte 1: Bit7~Bit6 => 00, Normal data packet + => 01, Absolute coordination packet + => 10, Notify packet + Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up. + When both fingers are up, the last two reports have zero valid + bit. + Bit4 => arc + Bit3 => 1 + Bit2 => Left Button, 1 is pressed, 0 is released. + Bit1 => 0 + Bit0 => 1 +Byte 2: X coordinate (xpos[9:2]) +Byte 3: Y coordinate (ypos[9:2]) +Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0]) + Bit3~Bit2 => X coordinate (ypos[1:0]) + Bit5~Bit4 => y1_g + Bit7~Bit6 => x1_g + +Packet 2 (ABSOLUTE POSITION) + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| + 1 |0|1|V|A|1|R|1|0| 2 |X|X|X|X|X|X|X|X| 3 |Y|Y|Y|Y|Y|Y|Y|Y| 4 |x|x|y|y|X|X|Y|Y| + |---------------| |---------------| |---------------| |---------------| + +Byte 1: Bit7~Bit6 => 00, Normal data packet + => 01, Absolute coordinates packet + => 10, Notify packet + Bit5 => Valid bit, 0 means that the coordinate is invalid or finger up. + When both fingers are up, the last two reports have zero valid + bit. + Bit4 => arc + Bit3 => 1 + Bit2 => Right Button, 1 is pressed, 0 is released. + Bit1 => 1 + Bit0 => 0 +Byte 2: X coordinate (xpos[9:2]) +Byte 3: Y coordinate (ypos[9:2]) +Byte 4: Bit1~Bit0 => Y coordinate (xpos[1:0]) + Bit3~Bit2 => X coordinate (ypos[1:0]) + Bit5~Bit4 => y2_g + Bit7~Bit6 => x2_g + +Notify Packet for STL3888-A0 + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| + 1 |1|0|1|P|1|M|R|L| 2 |C|C|C|C|C|C|C|C| 3 |0|0|F|F|0|0|0|i| 4 |r|l|d|u|0|0|0|0| + |---------------| |---------------| |---------------| |---------------| + +Byte 1: Bit7~Bit6 => 00, Normal data packet + => 01, Absolute coordination packet + => 10, Notify packet + Bit5 => 1 + Bit4 => when in absolute coordinates mode (valid when EN_PKT_GO is 1): + 0: left button is generated by the on-pad command + 1: left button is generated by the external button + Bit3 => 1 + Bit2 => Middle Button, 1 is pressed, 0 is not pressed. + Bit1 => Right Button, 1 is pressed, 0 is not pressed. + Bit0 => Left Button, 1 is pressed, 0 is not pressed. +Byte 2: Message Type => 0xB7 (Multi Finger, Multi Coordinate mode) +Byte 3: Bit7~Bit6 => Don't care + Bit5~Bit4 => Number of fingers + Bit3~Bit1 => Reserved + Bit0 => 1: enter gesture mode; 0: leaving gesture mode +Byte 4: Bit7 => scroll right button + Bit6 => scroll left button + Bit5 => scroll down button + Bit4 => scroll up button + * Note that if gesture and additional button (Bit4~Bit7) + happen at the same time, the button information will not + be sent. + Bit3~Bit0 => Reserved + +Sample sequence of Multi-finger, Multi-coordinate mode: + + notify packet (valid bit == 1), abs pkt 1, abs pkt 2, abs pkt 1, + abs pkt 2, ..., notify packet(valid bit == 0) + +============================================================================== +* FSP Enable/Disable packet +============================================================================== + Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +BYTE |---------------|BYTE |---------------|BYTE|---------------|BYTE|---------------| + 1 |Y|X|0|0|1|M|R|L| 2 |0|1|0|1|1|0|1|E| 3 | | | | | | | | | 4 | | | | | | | | | + |---------------| |---------------| |---------------| |---------------| + +FSP will send out enable/disable packet when FSP receive PS/2 enable/disable +command. Host will receive the packet which Middle, Right, Left button will +be set. The packet only use byte 0 and byte 1 as a pattern of original packet. +Ignore the other bytes of the packet. + +Byte 1: Bit7 => 0, Y overflow + Bit6 => 0, X overflow + Bit5 => 0, Y sign bit + Bit4 => 0, X sign bit + Bit3 => 1 + Bit2 => 1, Middle Button + Bit1 => 1, Right Button + Bit0 => 1, Left Button +Byte 2: Bit7~1 => (0101101b) + Bit0 => 1 = Enable + 0 = Disable +Byte 3: Don't care +Byte 4: Don't care (MOUSE ID 3, 4) +Byte 5~8: Don't care (Absolute packet) + +============================================================================== +* PS/2 Command Set +============================================================================== + +FSP supports basic PS/2 commanding set and modes, refer to following URL for +details about PS/2 commands: + +http://www.computer-engineering.org/index.php?title=PS/2_Mouse_Interface + +============================================================================== +* Programming Sequence for Determining Packet Parsing Flow +============================================================================== +1. Identify FSP by reading device ID(0x00) and version(0x01) register + +2. Determine number of buttons by reading status2 (0x0b) register + + buttons = reg[0x0b] & 0x30 + + if buttons == 0x30 or buttons == 0x20: + # two/four buttons + Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse' + section A for packet parsing detail(ignore byte 4, bit ~ 7) + elif buttons == 0x10: + # 6 buttons + Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse' + section B for packet parsing detail + elif buttons == 0x00: + # 6 buttons + Refer to 'Finger Sensing Pad PS/2 Mouse Intellimouse' + section A for packet parsing detail + +============================================================================== +* Programming Sequence for Register Reading/Writing +============================================================================== + +Register inversion requirement: + + Following values needed to be inverted(the '~' operator in C) before being +sent to FSP: + + 0xe9, 0xee, 0xf2 and 0xff. + +Register swapping requirement: + + Following values needed to have their higher 4 bits and lower 4 bits being +swapped before being sent to FSP: + + 10, 20, 40, 60, 80, 100 and 200. + +Register reading sequence: + + 1. send 0xf3 PS/2 command to FSP; + + 2. send 0x66 PS/2 command to FSP; + + 3. send 0x88 PS/2 command to FSP; + + 4. send 0xf3 PS/2 command to FSP; + + 5. if the register address being to read is not required to be + inverted(refer to the 'Register inversion requirement' section), + goto step 6 + + 5a. send 0x68 PS/2 command to FSP; + + 5b. send the inverted register address to FSP and goto step 8; + + 6. if the register address being to read is not required to be + swapped(refer to the 'Register swapping requirement' section), + goto step 7 + + 6a. send 0xcc PS/2 command to FSP; + + 6b. send the swapped register address to FSP and goto step 8; + + 7. send 0x66 PS/2 command to FSP; + + 7a. send the original register address to FSP and goto step 8; + + 8. send 0xe9(status request) PS/2 command to FSP; + + 9. the response read from FSP should be the requested register value. + +Register writing sequence: + + 1. send 0xf3 PS/2 command to FSP; + + 2. if the register address being to write is not required to be + inverted(refer to the 'Register inversion requirement' section), + goto step 3 + + 2a. send 0x74 PS/2 command to FSP; + + 2b. send the inverted register address to FSP and goto step 5; + + 3. if the register address being to write is not required to be + swapped(refer to the 'Register swapping requirement' section), + goto step 4 + + 3a. send 0x77 PS/2 command to FSP; + + 3b. send the swapped register address to FSP and goto step 5; + + 4. send 0x55 PS/2 command to FSP; + + 4a. send the register address to FSP and goto step 5; + + 5. send 0xf3 PS/2 command to FSP; + + 6. if the register value being to write is not required to be + inverted(refer to the 'Register inversion requirement' section), + goto step 7 + + 6a. send 0x47 PS/2 command to FSP; + + 6b. send the inverted register value to FSP and goto step 9; + + 7. if the register value being to write is not required to be + swapped(refer to the 'Register swapping requirement' section), + goto step 8 + + 7a. send 0x44 PS/2 command to FSP; + + 7b. send the swapped register value to FSP and goto step 9; + + 8. send 0x33 PS/2 command to FSP; + + 8a. send the register value to FSP; + + 9. the register writing sequence is completed. + +============================================================================== +* Register Listing +============================================================================== + +offset width default r/w name +0x00 bit7~bit0 0x01 RO device ID + +0x01 bit7~bit0 0xc0 RW version ID + +0x02 bit7~bit0 0x01 RO vendor ID + +0x03 bit7~bit0 0x01 RO product ID + +0x04 bit3~bit0 0x01 RW revision ID + +0x0b RO test mode status 1 + bit3 1 RO 0: rotate 180 degree, 1: no rotation + + bit5~bit4 RO number of buttons + 11 => 2, lbtn/rbtn + 10 => 4, lbtn/rbtn/scru/scrd + 01 => 6, lbtn/rbtn/scru/scrd/scrl/scrr + 00 => 6, lbtn/rbtn/scru/scrd/fbtn/bbtn + +0x0f RW register file page control + bit0 0 RW 1 to enable page 1 register files + +0x10 RW system control 1 + bit0 1 RW Reserved, must be 1 + bit1 0 RW Reserved, must be 0 + bit4 1 RW Reserved, must be 0 + bit5 0 RW register clock gating enable + 0: read only, 1: read/write enable + (Note that following registers does not require clock gating being + enabled prior to write: 05 06 07 08 09 0c 0f 10 11 12 16 17 18 23 2e + 40 41 42 43.) + +0x31 RW on-pad command detection + bit7 0 RW on-pad command left button down tag + enable + 0: disable, 1: enable + +0x34 RW on-pad command control 5 + bit4~bit0 0x05 RW XLO in 0s/4/1, so 03h = 0010.1b = 2.5 + (Note that position unit is in 0.5 scanline) + + bit7 0 RW on-pad tap zone enable + 0: disable, 1: enable + +0x35 RW on-pad command control 6 + bit4~bit0 0x1d RW XHI in 0s/4/1, so 19h = 1100.1b = 12.5 + (Note that position unit is in 0.5 scanline) + +0x36 RW on-pad command control 7 + bit4~bit0 0x04 RW YLO in 0s/4/1, so 03h = 0010.1b = 2.5 + (Note that position unit is in 0.5 scanline) + +0x37 RW on-pad command control 8 + bit4~bit0 0x13 RW YHI in 0s/4/1, so 11h = 1000.1b = 8.5 + (Note that position unit is in 0.5 scanline) + +0x40 RW system control 5 + bit1 0 RW FSP Intellimouse mode enable + 0: disable, 1: enable + + bit2 0 RW movement + abs. coordinate mode enable + 0: disable, 1: enable + (Note that this function has the functionality of bit 1 even when + bit 1 is not set. However, the format is different from that of bit 1. + In addition, when bit 1 and bit 2 are set at the same time, bit 2 will + override bit 1.) + + bit3 0 RW abs. coordinate only mode enable + 0: disable, 1: enable + (Note that this function has the functionality of bit 1 even when + bit 1 is not set. However, the format is different from that of bit 1. + In addition, when bit 1, bit 2 and bit 3 are set at the same time, + bit 3 will override bit 1 and 2.) + + bit5 0 RW auto switch enable + 0: disable, 1: enable + + bit6 0 RW G0 abs. + notify packet format enable + 0: disable, 1: enable + (Note that the absolute/relative coordinate output still depends on + bit 2 and 3. That is, if any of those bit is 1, host will receive + absolute coordinates; otherwise, host only receives packets with + relative coordinate.) + +0x43 RW on-pad control + bit0 0 RW on-pad control enable + 0: disable, 1: enable + (Note that if this bit is cleared, bit 3/5 will be ineffective) + + bit3 0 RW on-pad fix vertical scrolling enable + 0: disable, 1: enable + + bit5 0 RW on-pad fix horizontal scrolling enable + 0: disable, 1: enable diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 90bef5d498f..3feeb3af8ab 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -107,6 +107,14 @@ config MOUSE_PS2_ELANTECH entries. For further information, see . +config MOUSE_PS2_SENTELIC + bool "Sentelic Finger Sensing Pad PS/2 protocol extension" + depends on MOUSE_PS2 + help + Say Y here if you have a laptop (such as MSI WIND Netbook) + with Sentelic Finger Sensing Pad touchpad. + + If unsure, say N. config MOUSE_PS2_TOUCHKIT bool "eGalax TouchKit PS/2 protocol extension" diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index ea58c9a372b..570c84a4a65 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -27,5 +27,6 @@ psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o +psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index b407b355dce..df318887ca0 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -30,6 +30,7 @@ #include "trackpoint.h" #include "touchkit_ps2.h" #include "elantech.h" +#include "sentelic.h" #define DRIVER_DESC "PS/2 mouse driver" @@ -666,6 +667,20 @@ static int psmouse_extensions(struct psmouse *psmouse, max_proto = PSMOUSE_IMEX; } +/* + * Try Finger Sensing Pad + */ + if (max_proto > PSMOUSE_IMEX) { + if (fsp_detect(psmouse, set_properties) == 0) { + if (!set_properties || fsp_init(psmouse) == 0) + return PSMOUSE_FSP; +/* + * Init failed, try basic relative protocols + */ + max_proto = PSMOUSE_IMEX; + } + } + if (max_proto > PSMOUSE_IMEX) { if (genius_detect(psmouse, set_properties) == 0) return PSMOUSE_GENPS; @@ -813,7 +828,16 @@ static const struct psmouse_protocol psmouse_protocols[] = { .detect = elantech_detect, .init = elantech_init, }, - #endif +#endif +#ifdef CONFIG_MOUSE_PS2_SENTELIC + { + .type = PSMOUSE_FSP, + .name = "FSPPS/2", + .alias = "fsp", + .detect = fsp_detect, + .init = fsp_init, + }, +#endif { .type = PSMOUSE_CORTRON, .name = "CortronPS/2", diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index e3562daeb2e..cca1744c2a0 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -91,6 +91,7 @@ enum psmouse_type { PSMOUSE_CORTRON, PSMOUSE_HGPK, PSMOUSE_ELANTECH, + PSMOUSE_FSP, PSMOUSE_AUTO /* This one should always be last */ }; diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c new file mode 100644 index 00000000000..97b1e72855a --- /dev/null +++ b/drivers/input/mouse/sentelic.c @@ -0,0 +1,867 @@ +/*- + * Finger Sensing Pad PS/2 mouse driver. + * + * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. + * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "psmouse.h" +#include "sentelic.h" + +/* + * Timeout for FSP PS/2 command only (in milliseconds). + */ +#define FSP_CMD_TIMEOUT 200 +#define FSP_CMD_TIMEOUT2 30 + +/** Driver version. */ +static const char fsp_drv_ver[] = "1.0.0-K"; + +/* + * Make sure that the value being sent to FSP will not conflict with + * possible sample rate values. + */ +static unsigned char fsp_test_swap_cmd(unsigned char reg_val) +{ + switch (reg_val) { + case 10: case 20: case 40: case 60: case 80: case 100: case 200: + /* + * The requested value being sent to FSP matched to possible + * sample rates, swap the given value such that the hardware + * wouldn't get confused. + */ + return (reg_val >> 4) | (reg_val << 4); + default: + return reg_val; /* swap isn't necessary */ + } +} + +/* + * Make sure that the value being sent to FSP will not conflict with certain + * commands. + */ +static unsigned char fsp_test_invert_cmd(unsigned char reg_val) +{ + switch (reg_val) { + case 0xe9: case 0xee: case 0xf2: case 0xff: + /* + * The requested value being sent to FSP matched to certain + * commands, inverse the given value such that the hardware + * wouldn't get confused. + */ + return ~reg_val; + default: + return reg_val; /* inversion isn't necessary */ + } +} + +static int fsp_reg_read(struct psmouse *psmouse, int reg_addr, int *reg_val) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[3]; + unsigned char addr; + int rc = -1; + + /* + * We need to shut off the device and switch it into command + * mode so we don't confuse our protocol handler. We don't need + * to do that for writes because sysfs set helper does this for + * us. + */ + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + mutex_lock(&ps2dev->cmd_mutex); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + /* should return 0xfe(request for resending) */ + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); + /* should return 0xfc(failed) */ + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + if ((addr = fsp_test_invert_cmd(reg_addr)) != reg_addr) { + ps2_sendbyte(ps2dev, 0x68, FSP_CMD_TIMEOUT2); + } else if ((addr = fsp_test_swap_cmd(reg_addr)) != reg_addr) { + /* swapping is required */ + ps2_sendbyte(ps2dev, 0xcc, FSP_CMD_TIMEOUT2); + /* expect 0xfe */ + } else { + /* swapping isn't necessary */ + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); + /* expect 0xfe */ + } + /* should return 0xfc(failed) */ + ps2_sendbyte(ps2dev, addr, FSP_CMD_TIMEOUT); + + if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) < 0) + goto out; + + *reg_val = param[2]; + rc = 0; + + out: + mutex_unlock(&ps2dev->cmd_mutex); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); + dev_dbg(&ps2dev->serio->dev, "READ REG: 0x%02x is 0x%02x (rc = %d)\n", + reg_addr, *reg_val, rc); + return rc; +} + +static int fsp_reg_write(struct psmouse *psmouse, int reg_addr, int reg_val) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char v; + int rc = -1; + + mutex_lock(&ps2dev->cmd_mutex); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + if ((v = fsp_test_invert_cmd(reg_addr)) != reg_addr) { + /* inversion is required */ + ps2_sendbyte(ps2dev, 0x74, FSP_CMD_TIMEOUT2); + } else { + if ((v = fsp_test_swap_cmd(reg_addr)) != reg_addr) { + /* swapping is required */ + ps2_sendbyte(ps2dev, 0x77, FSP_CMD_TIMEOUT2); + } else { + /* swapping isn't necessary */ + ps2_sendbyte(ps2dev, 0x55, FSP_CMD_TIMEOUT2); + } + } + /* write the register address in correct order */ + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + return -1; + + if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { + /* inversion is required */ + ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2); + } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) { + /* swapping is required */ + ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2); + } else { + /* swapping isn't necessary */ + ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2); + } + + /* write the register value in correct order */ + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); + rc = 0; + + out: + mutex_unlock(&ps2dev->cmd_mutex); + dev_dbg(&ps2dev->serio->dev, "WRITE REG: 0x%02x to 0x%02x (rc = %d)\n", + reg_addr, reg_val, rc); + return rc; +} + +/* Enable register clock gating for writing certain registers */ +static int fsp_reg_write_enable(struct psmouse *psmouse, bool enable) +{ + int v, nv; + + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL1, &v) == -1) + return -1; + + if (enable) + nv = v | FSP_BIT_EN_REG_CLK; + else + nv = v & ~FSP_BIT_EN_REG_CLK; + + /* only write if necessary */ + if (nv != v) + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL1, nv) == -1) + return -1; + + return 0; +} + +static int fsp_page_reg_read(struct psmouse *psmouse, int *reg_val) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[3]; + int rc = -1; + + ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE); + psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); + mutex_lock(&ps2dev->cmd_mutex); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + ps2_sendbyte(ps2dev, 0x66, FSP_CMD_TIMEOUT2); + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + ps2_sendbyte(ps2dev, 0x83, FSP_CMD_TIMEOUT2); + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); + + /* get the returned result */ + if (__ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) + goto out; + + *reg_val = param[2]; + rc = 0; + + out: + mutex_unlock(&ps2dev->cmd_mutex); + ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); + psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); + dev_dbg(&ps2dev->serio->dev, "READ PAGE REG: 0x%02x (rc = %d)\n", + *reg_val, rc); + return rc; +} + +static int fsp_page_reg_write(struct psmouse *psmouse, int reg_val) +{ + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char v; + int rc = -1; + + mutex_lock(&ps2dev->cmd_mutex); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + goto out; + + ps2_sendbyte(ps2dev, 0x38, FSP_CMD_TIMEOUT2); + ps2_sendbyte(ps2dev, 0x88, FSP_CMD_TIMEOUT2); + + if (ps2_sendbyte(ps2dev, 0xf3, FSP_CMD_TIMEOUT) < 0) + return -1; + + if ((v = fsp_test_invert_cmd(reg_val)) != reg_val) { + ps2_sendbyte(ps2dev, 0x47, FSP_CMD_TIMEOUT2); + } else if ((v = fsp_test_swap_cmd(reg_val)) != reg_val) { + /* swapping is required */ + ps2_sendbyte(ps2dev, 0x44, FSP_CMD_TIMEOUT2); + } else { + /* swapping isn't necessary */ + ps2_sendbyte(ps2dev, 0x33, FSP_CMD_TIMEOUT2); + } + + ps2_sendbyte(ps2dev, v, FSP_CMD_TIMEOUT2); + rc = 0; + + out: + mutex_unlock(&ps2dev->cmd_mutex); + dev_dbg(&ps2dev->serio->dev, "WRITE PAGE REG: to 0x%02x (rc = %d)\n", + reg_val, rc); + return rc; +} + +static int fsp_get_version(struct psmouse *psmouse, int *version) +{ + if (fsp_reg_read(psmouse, FSP_REG_VERSION, version)) + return -EIO; + + return 0; +} + +static int fsp_get_revision(struct psmouse *psmouse, int *rev) +{ + if (fsp_reg_read(psmouse, FSP_REG_REVISION, rev)) + return -EIO; + + return 0; +} + +static int fsp_get_buttons(struct psmouse *psmouse, int *btn) +{ + static const int buttons[] = { + 0x16, /* Left/Middle/Right/Forward/Backward & Scroll Up/Down */ + 0x06, /* Left/Middle/Right & Scroll Up/Down/Right/Left */ + 0x04, /* Left/Middle/Right & Scroll Up/Down */ + 0x02, /* Left/Middle/Right */ + }; + int val; + + if (fsp_reg_read(psmouse, FSP_REG_TMOD_STATUS1, &val) == -1) + return -EIO; + + *btn = buttons[(val & 0x30) >> 4]; + return 0; +} + +/* Enable on-pad command tag output */ +static int fsp_opc_tag_enable(struct psmouse *psmouse, bool enable) +{ + int v, nv; + int res = 0; + + if (fsp_reg_read(psmouse, FSP_REG_OPC_QDOWN, &v) == -1) { + dev_err(&psmouse->ps2dev.serio->dev, "Unable get OPC state.\n"); + return -EIO; + } + + if (enable) + nv = v | FSP_BIT_EN_OPC_TAG; + else + nv = v & ~FSP_BIT_EN_OPC_TAG; + + /* only write if necessary */ + if (nv != v) { + fsp_reg_write_enable(psmouse, true); + res = fsp_reg_write(psmouse, FSP_REG_OPC_QDOWN, nv); + fsp_reg_write_enable(psmouse, false); + } + + if (res != 0) { + dev_err(&psmouse->ps2dev.serio->dev, + "Unable to enable OPC tag.\n"); + res = -EIO; + } + + return res; +} + +static int fsp_onpad_vscr(struct psmouse *psmouse, bool enable) +{ + struct fsp_data *pad = psmouse->private; + int val; + + if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val)) + return -EIO; + + pad->vscroll = enable; + + if (enable) + val |= (FSP_BIT_FIX_VSCR | FSP_BIT_ONPAD_ENABLE); + else + val &= ~FSP_BIT_FIX_VSCR; + + if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val)) + return -EIO; + + return 0; +} + +static int fsp_onpad_hscr(struct psmouse *psmouse, bool enable) +{ + struct fsp_data *pad = psmouse->private; + int val, v2; + + if (fsp_reg_read(psmouse, FSP_REG_ONPAD_CTL, &val)) + return -EIO; + + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &v2)) + return -EIO; + + pad->hscroll = enable; + + if (enable) { + val |= (FSP_BIT_FIX_HSCR | FSP_BIT_ONPAD_ENABLE); + v2 |= FSP_BIT_EN_MSID6; + } else { + val &= ~FSP_BIT_FIX_HSCR; + v2 &= ~(FSP_BIT_EN_MSID6 | FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8); + } + + if (fsp_reg_write(psmouse, FSP_REG_ONPAD_CTL, val)) + return -EIO; + + /* reconfigure horizontal scrolling packet output */ + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, v2)) + return -EIO; + + return 0; +} + +/* + * Write device specific initial parameters. + * + * ex: 0xab 0xcd - write oxcd into register 0xab + */ +static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + unsigned long reg, val; + char *rest; + ssize_t retval; + + reg = simple_strtoul(buf, &rest, 16); + if (rest == buf || *rest != ' ' || reg > 0xff) + return -EINVAL; + + if (strict_strtoul(rest + 1, 16, &val) || val > 0xff) + return -EINVAL; + + if (fsp_reg_write_enable(psmouse, true)) + return -EIO; + + retval = fsp_reg_write(psmouse, reg, val) < 0 ? -EIO : count; + + fsp_reg_write_enable(psmouse, false); + + return count; +} + +PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg); + +static ssize_t fsp_attr_show_getreg(struct psmouse *psmouse, + void *data, char *buf) +{ + struct fsp_data *pad = psmouse->private; + + return sprintf(buf, "%02x%02x\n", pad->last_reg, pad->last_val); +} + +/* + * Read a register from device. + * + * ex: 0xab -- read content from register 0xab + */ +static ssize_t fsp_attr_set_getreg(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct fsp_data *pad = psmouse->private; + unsigned long reg; + int val; + + if (strict_strtoul(buf, 16, ®) || reg > 0xff) + return -EINVAL; + + if (fsp_reg_read(psmouse, reg, &val)) + return -EIO; + + pad->last_reg = reg; + pad->last_val = val; + + return count; +} + +PSMOUSE_DEFINE_ATTR(getreg, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_getreg, fsp_attr_set_getreg); + +static ssize_t fsp_attr_show_pagereg(struct psmouse *psmouse, + void *data, char *buf) +{ + int val = 0; + + if (fsp_page_reg_read(psmouse, &val)) + return -EIO; + + return sprintf(buf, "%02x\n", val); +} + +static ssize_t fsp_attr_set_pagereg(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + unsigned long val; + + if (strict_strtoul(buf, 16, &val) || val > 0xff) + return -EINVAL; + + if (fsp_page_reg_write(psmouse, val)) + return -EIO; + + return count; +} + +PSMOUSE_DEFINE_ATTR(page, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_pagereg, fsp_attr_set_pagereg); + +static ssize_t fsp_attr_show_vscroll(struct psmouse *psmouse, + void *data, char *buf) +{ + struct fsp_data *pad = psmouse->private; + + return sprintf(buf, "%d\n", pad->vscroll); +} + +static ssize_t fsp_attr_set_vscroll(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + unsigned long val; + + if (strict_strtoul(buf, 10, &val) || val > 1) + return -EINVAL; + + fsp_onpad_vscr(psmouse, val); + + return count; +} + +PSMOUSE_DEFINE_ATTR(vscroll, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_vscroll, fsp_attr_set_vscroll); + +static ssize_t fsp_attr_show_hscroll(struct psmouse *psmouse, + void *data, char *buf) +{ + struct fsp_data *pad = psmouse->private; + + return sprintf(buf, "%d\n", pad->hscroll); +} + +static ssize_t fsp_attr_set_hscroll(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + unsigned long val; + + if (strict_strtoul(buf, 10, &val) || val > 1) + return -EINVAL; + + fsp_onpad_hscr(psmouse, val); + + return count; +} + +PSMOUSE_DEFINE_ATTR(hscroll, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_hscroll, fsp_attr_set_hscroll); + +static ssize_t fsp_attr_show_flags(struct psmouse *psmouse, + void *data, char *buf) +{ + struct fsp_data *pad = psmouse->private; + + return sprintf(buf, "%c\n", + pad->flags & FSPDRV_FLAG_EN_OPC ? 'C' : 'c'); +} + +static ssize_t fsp_attr_set_flags(struct psmouse *psmouse, void *data, + const char *buf, size_t count) +{ + struct fsp_data *pad = psmouse->private; + size_t i; + + for (i = 0; i < count; i++) { + switch (buf[i]) { + case 'C': + pad->flags |= FSPDRV_FLAG_EN_OPC; + break; + case 'c': + pad->flags &= ~FSPDRV_FLAG_EN_OPC; + break; + default: + return -EINVAL; + } + } + return count; +} + +PSMOUSE_DEFINE_ATTR(flags, S_IWUSR | S_IRUGO, NULL, + fsp_attr_show_flags, fsp_attr_set_flags); + +static ssize_t fsp_attr_show_ver(struct psmouse *psmouse, + void *data, char *buf) +{ + return sprintf(buf, "Sentelic FSP kernel module %s\n", fsp_drv_ver); +} + +PSMOUSE_DEFINE_RO_ATTR(ver, S_IRUGO, NULL, fsp_attr_show_ver); + +static struct attribute *fsp_attributes[] = { + &psmouse_attr_setreg.dattr.attr, + &psmouse_attr_getreg.dattr.attr, + &psmouse_attr_page.dattr.attr, + &psmouse_attr_vscroll.dattr.attr, + &psmouse_attr_hscroll.dattr.attr, + &psmouse_attr_flags.dattr.attr, + &psmouse_attr_ver.dattr.attr, + NULL +}; + +static struct attribute_group fsp_attribute_group = { + .attrs = fsp_attributes, +}; + +#ifdef FSP_DEBUG +static void fsp_packet_debug(unsigned char packet[]) +{ + static unsigned int ps2_packet_cnt; + static unsigned int ps2_last_second; + unsigned int jiffies_msec; + + ps2_packet_cnt++; + jiffies_msec = jiffies_to_msecs(jiffies); + printk(KERN_DEBUG "%08dms PS/2 packets: %02x, %02x, %02x, %02x\n", + jiffies_msec, packet[0], packet[1], packet[2], packet[3]); + + if (jiffies_msec - ps2_last_second > 1000) { + printk(KERN_DEBUG "PS/2 packets/sec = %d\n", ps2_packet_cnt); + ps2_packet_cnt = 0; + ps2_last_second = jiffies_msec; + } +} +#else +static void fsp_packet_debug(unsigned char packet[]) +{ +} +#endif + +static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse) +{ + struct input_dev *dev = psmouse->dev; + struct fsp_data *ad = psmouse->private; + unsigned char *packet = psmouse->packet; + unsigned char button_status = 0, lscroll = 0, rscroll = 0; + int rel_x, rel_y; + + if (psmouse->pktcnt < 4) + return PSMOUSE_GOOD_DATA; + + /* + * Full packet accumulated, process it + */ + + switch (psmouse->packet[0] >> FSP_PKT_TYPE_SHIFT) { + case FSP_PKT_TYPE_ABS: + dev_warn(&psmouse->ps2dev.serio->dev, + "Unexpected absolute mode packet, ignored.\n"); + break; + + case FSP_PKT_TYPE_NORMAL_OPC: + /* on-pad click, filter it if necessary */ + if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC) + packet[0] &= ~BIT(0); + /* fall through */ + + case FSP_PKT_TYPE_NORMAL: + /* normal packet */ + /* special packet data translation from on-pad packets */ + if (packet[3] != 0) { + if (packet[3] & BIT(0)) + button_status |= 0x01; /* wheel down */ + if (packet[3] & BIT(1)) + button_status |= 0x0f; /* wheel up */ + if (packet[3] & BIT(2)) + button_status |= BIT(5);/* horizontal left */ + if (packet[3] & BIT(3)) + button_status |= BIT(4);/* horizontal right */ + /* push back to packet queue */ + if (button_status != 0) + packet[3] = button_status; + rscroll = (packet[3] >> 4) & 1; + lscroll = (packet[3] >> 5) & 1; + } + /* + * Processing wheel up/down and extra button events + */ + input_report_rel(dev, REL_WHEEL, + (int)(packet[3] & 8) - (int)(packet[3] & 7)); + input_report_rel(dev, REL_HWHEEL, lscroll - rscroll); + input_report_key(dev, BTN_BACK, lscroll); + input_report_key(dev, BTN_FORWARD, rscroll); + + /* + * Standard PS/2 Mouse + */ + input_report_key(dev, BTN_LEFT, packet[0] & 1); + input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); + input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); + + rel_x = packet[1] ? (int)packet[1] - (int)((packet[0] << 4) & 0x100) : 0; + rel_y = packet[2] ? (int)((packet[0] << 3) & 0x100) - (int)packet[2] : 0; + + input_report_rel(dev, REL_X, rel_x); + input_report_rel(dev, REL_Y, rel_y); + break; + } + + input_sync(dev); + + fsp_packet_debug(packet); + + return PSMOUSE_FULL_PACKET; +} + +static int fsp_activate_protocol(struct psmouse *psmouse) +{ + struct fsp_data *pad = psmouse->private; + struct ps2dev *ps2dev = &psmouse->ps2dev; + unsigned char param[2]; + int val; + + /* + * Standard procedure to enter FSP Intellimouse mode + * (scrolling wheel, 4th and 5th buttons) + */ + param[0] = 200; + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); + param[0] = 200; + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); + param[0] = 80; + ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); + + ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); + if (param[0] != 0x04) { + dev_err(&psmouse->ps2dev.serio->dev, + "Unable to enable 4 bytes packet format.\n"); + return -EIO; + } + + if (fsp_reg_read(psmouse, FSP_REG_SYSCTL5, &val)) { + dev_err(&psmouse->ps2dev.serio->dev, + "Unable to read SYSCTL5 register.\n"); + return -EIO; + } + + val &= ~(FSP_BIT_EN_MSID7 | FSP_BIT_EN_MSID8 | FSP_BIT_EN_AUTO_MSID8); + /* Ensure we are not in absolute mode */ + val &= ~FSP_BIT_EN_PKT_G0; + if (pad->buttons == 0x06) { + /* Left/Middle/Right & Scroll Up/Down/Right/Left */ + val |= FSP_BIT_EN_MSID6; + } + + if (fsp_reg_write(psmouse, FSP_REG_SYSCTL5, val)) { + dev_err(&psmouse->ps2dev.serio->dev, + "Unable to set up required mode bits.\n"); + return -EIO; + } + + /* + * Enable OPC tags such that driver can tell the difference between + * on-pad and real button click + */ + if (fsp_opc_tag_enable(psmouse, true)) + dev_warn(&psmouse->ps2dev.serio->dev, + "Failed to enable OPC tag mode.\n"); + + /* Enable on-pad vertical and horizontal scrolling */ + fsp_onpad_vscr(psmouse, true); + fsp_onpad_hscr(psmouse, true); + + return 0; +} + +int fsp_detect(struct psmouse *psmouse, int set_properties) +{ + int id; + + if (fsp_reg_read(psmouse, FSP_REG_DEVICE_ID, &id)) + return -EIO; + + if (id != 0x01) + return -ENODEV; + + if (set_properties) { + psmouse->vendor = "Sentelic"; + psmouse->name = "FingerSensingPad"; + } + + return 0; +} + +static void fsp_reset(struct psmouse *psmouse) +{ + fsp_opc_tag_enable(psmouse, false); + fsp_onpad_vscr(psmouse, false); + fsp_onpad_hscr(psmouse, false); +} + +static void fsp_disconnect(struct psmouse *psmouse) +{ + sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, + &fsp_attribute_group); + + fsp_reset(psmouse); + kfree(psmouse->private); +} + +static int fsp_reconnect(struct psmouse *psmouse) +{ + int version; + + if (fsp_detect(psmouse, 0)) + return -ENODEV; + + if (fsp_get_version(psmouse, &version)) + return -ENODEV; + + if (fsp_activate_protocol(psmouse)) + return -EIO; + + return 0; +} + +int fsp_init(struct psmouse *psmouse) +{ + struct fsp_data *priv; + int ver, rev, buttons; + int error; + + if (fsp_get_version(psmouse, &ver) || + fsp_get_revision(psmouse, &rev) || + fsp_get_buttons(psmouse, &buttons)) { + return -ENODEV; + } + + printk(KERN_INFO + "Finger Sensing Pad, hw: %d.%d.%d, sw: %s, buttons: %d\n", + ver >> 4, ver & 0x0F, rev, fsp_drv_ver, buttons & 7); + + psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->ver = ver; + priv->rev = rev; + priv->buttons = buttons; + + /* enable on-pad click by default */ + priv->flags |= FSPDRV_FLAG_EN_OPC; + + /* Set up various supported input event bits */ + __set_bit(BTN_BACK, psmouse->dev->keybit); + __set_bit(BTN_FORWARD, psmouse->dev->keybit); + __set_bit(REL_WHEEL, psmouse->dev->relbit); + __set_bit(REL_HWHEEL, psmouse->dev->relbit); + + psmouse->protocol_handler = fsp_process_byte; + psmouse->disconnect = fsp_disconnect; + psmouse->reconnect = fsp_reconnect; + psmouse->cleanup = fsp_reset; + psmouse->pktsize = 4; + + /* set default packet output based on number of buttons we found */ + error = fsp_activate_protocol(psmouse); + if (error) + goto err_out; + + error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, + &fsp_attribute_group); + if (error) { + dev_err(&psmouse->ps2dev.serio->dev, + "Failed to create sysfs attributes (%d)", error); + goto err_out; + } + + return 0; + + err_out: + kfree(psmouse->private); + psmouse->private = NULL; + return error; +} diff --git a/drivers/input/mouse/sentelic.h b/drivers/input/mouse/sentelic.h new file mode 100644 index 00000000000..083559c7282 --- /dev/null +++ b/drivers/input/mouse/sentelic.h @@ -0,0 +1,98 @@ +/*- + * Finger Sensing Pad PS/2 mouse driver. + * + * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. + * Copyright (C) 2005-2009 Tai-hwa Liang, Sentelic Corporation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __SENTELIC_H +#define __SENTELIC_H + +/* Finger-sensing Pad information registers */ +#define FSP_REG_DEVICE_ID 0x00 +#define FSP_REG_VERSION 0x01 +#define FSP_REG_REVISION 0x04 +#define FSP_REG_TMOD_STATUS1 0x0B +#define FSP_BIT_NO_ROTATION BIT(3) +#define FSP_REG_PAGE_CTRL 0x0F + +/* Finger-sensing Pad control registers */ +#define FSP_REG_SYSCTL1 0x10 +#define FSP_BIT_EN_REG_CLK BIT(5) +#define FSP_REG_OPC_QDOWN 0x31 +#define FSP_BIT_EN_OPC_TAG BIT(7) +#define FSP_REG_OPTZ_XLO 0x34 +#define FSP_REG_OPTZ_XHI 0x35 +#define FSP_REG_OPTZ_YLO 0x36 +#define FSP_REG_OPTZ_YHI 0x37 +#define FSP_REG_SYSCTL5 0x40 +#define FSP_BIT_90_DEGREE BIT(0) +#define FSP_BIT_EN_MSID6 BIT(1) +#define FSP_BIT_EN_MSID7 BIT(2) +#define FSP_BIT_EN_MSID8 BIT(3) +#define FSP_BIT_EN_AUTO_MSID8 BIT(5) +#define FSP_BIT_EN_PKT_G0 BIT(6) + +#define FSP_REG_ONPAD_CTL 0x43 +#define FSP_BIT_ONPAD_ENABLE BIT(0) +#define FSP_BIT_ONPAD_FBBB BIT(1) +#define FSP_BIT_FIX_VSCR BIT(3) +#define FSP_BIT_FIX_HSCR BIT(5) +#define FSP_BIT_DRAG_LOCK BIT(6) + +/* Finger-sensing Pad packet formating related definitions */ + +/* absolute packet type */ +#define FSP_PKT_TYPE_NORMAL (0x00) +#define FSP_PKT_TYPE_ABS (0x01) +#define FSP_PKT_TYPE_NOTIFY (0x02) +#define FSP_PKT_TYPE_NORMAL_OPC (0x03) +#define FSP_PKT_TYPE_SHIFT (6) + +#ifdef __KERNEL__ + +struct fsp_data { + unsigned char ver; /* hardware version */ + unsigned char rev; /* hardware revison */ + unsigned char buttons; /* Number of buttons */ + unsigned int flags; +#define FSPDRV_FLAG_EN_OPC (0x001) /* enable on-pad clicking */ + + bool vscroll; /* Vertical scroll zone enabled */ + bool hscroll; /* Horizontal scroll zone enabled */ + + unsigned char last_reg; /* Last register we requested read from */ + unsigned char last_val; +}; + +#ifdef CONFIG_MOUSE_PS2_SENTELIC +extern int fsp_detect(struct psmouse *psmouse, int set_properties); +extern int fsp_init(struct psmouse *psmouse); +#else +inline int fsp_detect(struct psmouse *psmouse, int set_properties) +{ + return -ENOSYS; +} +inline int fsp_init(struct psmouse *psmouse) +{ + return -ENOSYS; +} +#endif + +#endif /* __KERNEL__ */ + +#endif /* !__SENTELIC_H */ diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index be5bbbb8ae4..3a95b508bf2 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -161,7 +161,7 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout) * ps2_command() can only be called from a process context */ -int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) +int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) { int timeout; int send = (command >> 12) & 0xf; @@ -179,8 +179,6 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) return -1; } - mutex_lock(&ps2dev->cmd_mutex); - serio_pause_rx(ps2dev->serio); ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; ps2dev->cmdcnt = receive; @@ -231,7 +229,18 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) ps2dev->flags = 0; serio_continue_rx(ps2dev->serio); + return rc; +} +EXPORT_SYMBOL(__ps2_command); + +int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) +{ + int rc; + + mutex_lock(&ps2dev->cmd_mutex); + rc = __ps2_command(ps2dev, param, command); mutex_unlock(&ps2dev->cmd_mutex); + return rc; } EXPORT_SYMBOL(ps2_command); diff --git a/include/linux/libps2.h b/include/linux/libps2.h index b94534b7e26..fcf5fbe6a50 100644 --- a/include/linux/libps2.h +++ b/include/linux/libps2.h @@ -44,6 +44,7 @@ struct ps2dev { void ps2_init(struct ps2dev *ps2dev, struct serio *serio); int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout); void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout); +int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data); int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data); -- cgit v1.2.3-70-g09d2 From 196be0cd018068d545e1d764094c7b07aaf0bcfe Mon Sep 17 00:00:00 2001 From: Bing Zhao Date: Tue, 2 Jun 2009 14:29:38 -0700 Subject: Bluetooth: Add documentation for Marvell Bluetooth driver add btmrvl.txt to Documentation/ This patch incorporates a lot of comments given by Nicolas Pitre . Many thanks to Nicolas Pitre. Signed-off-by: Rahul Tank Signed-off-by: Bing Zhao Signed-off-by: Marcel Holtmann --- Documentation/00-INDEX | 2 + Documentation/btmrvl.txt | 119 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 Documentation/btmrvl.txt (limited to 'Documentation') diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index d05737aaa84..06b982affe7 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -82,6 +82,8 @@ block/ - info on the Block I/O (BIO) layer. blockdev/ - info on block devices & drivers +btmrvl.txt + - info on Marvell Bluetooth driver usage. cachetlb.txt - describes the cache/TLB flushing interfaces Linux uses. cdrom/ diff --git a/Documentation/btmrvl.txt b/Documentation/btmrvl.txt new file mode 100644 index 00000000000..34916a46c09 --- /dev/null +++ b/Documentation/btmrvl.txt @@ -0,0 +1,119 @@ +======================================================================= + README for btmrvl driver +======================================================================= + + +All commands are used via debugfs interface. + +===================== +Set/get driver configurations: + +Path: /debug/btmrvl/config/ + +gpiogap=[n] +hscfgcmd + These commands are used to configure the host sleep parameters. + bit 8:0 -- Gap + bit 16:8 -- GPIO + + where GPIO is the pin number of GPIO used to wake up the host. + It could be any valid GPIO pin# (e.g. 0-7) or 0xff (SDIO interface + wakeup will be used instead). + + where Gap is the gap in milli seconds between wakeup signal and + wakeup event, or 0xff for special host sleep setting. + + Usage: + # Use SDIO interface to wake up the host and set GAP to 0x80: + echo 0xff80 > /debug/btmrvl/config/gpiogap + echo 1 > /debug/btmrvl/config/hscfgcmd + + # Use GPIO pin #3 to wake up the host and set GAP to 0xff: + echo 0x03ff > /debug/btmrvl/config/gpiogap + echo 1 > /debug/btmrvl/config/hscfgcmd + +psmode=[n] +pscmd + These commands are used to enable/disable auto sleep mode + + where the option is: + 1 -- Enable auto sleep mode + 0 -- Disable auto sleep mode + + Usage: + # Enable auto sleep mode + echo 1 > /debug/btmrvl/config/psmode + echo 1 > /debug/btmrvl/config/pscmd + + # Disable auto sleep mode + echo 0 > /debug/btmrvl/config/psmode + echo 1 > /debug/btmrvl/config/pscmd + + +hsmode=[n] +hscmd + These commands are used to enable host sleep or wake up firmware + + where the option is: + 1 -- Enable host sleep + 0 -- Wake up firmware + + Usage: + # Enable host sleep + echo 1 > /debug/btmrvl/config/hsmode + echo 1 > /debug/btmrvl/config/hscmd + + # Wake up firmware + echo 0 > /debug/btmrvl/config/hsmode + echo 1 > /debug/btmrvl/config/hscmd + + +====================== +Get driver status: + +Path: /debug/btmrvl/status/ + +Usage: + cat /debug/btmrvl/status/ + +where the args are: + +curpsmode + This command displays current auto sleep status. + +psstate + This command display the power save state. + +hsstate + This command display the host sleep state. + +txdnldrdy + This command displays the value of Tx download ready flag. + + +===================== + +Use hcitool to issue raw hci command, refer to hcitool manual + + Usage: Hcitool cmd [Parameters] + + Interface Control Command + hcitool cmd 0x3f 0x5b 0xf5 0x01 0x00 --Enable All interface + hcitool cmd 0x3f 0x5b 0xf5 0x01 0x01 --Enable Wlan interface + hcitool cmd 0x3f 0x5b 0xf5 0x01 0x02 --Enable BT interface + hcitool cmd 0x3f 0x5b 0xf5 0x00 0x00 --Disable All interface + hcitool cmd 0x3f 0x5b 0xf5 0x00 0x01 --Disable Wlan interface + hcitool cmd 0x3f 0x5b 0xf5 0x00 0x02 --Disable BT interface + +======================================================================= + + +SD8688 firmware: + +/lib/firmware/sd8688_helper.bin +/lib/firmware/sd8688.bin + + +The images can be downloaded from: + +git.infradead.org/users/dwmw2/linux-firmware.git/libertas/ -- cgit v1.2.3-70-g09d2 From d6714c22b43fbcbead7e7b706ff270e15f04a791 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 22 Aug 2009 13:56:46 -0700 Subject: rcu: Renamings to increase RCU clarity Make RCU-sched, RCU-bh, and RCU-preempt be underlying implementations, with "RCU" defined in terms of one of the three. Update the outdated rcu_qsctr_inc() names, as these functions no longer increment anything. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: akpm@linux-foundation.org Cc: mathieu.desnoyers@polymtl.ca Cc: josht@linux.vnet.ibm.com Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org LKML-Reference: <12509746132696-git-send-email-> Signed-off-by: Ingo Molnar --- Documentation/RCU/trace.txt | 7 ++-- include/linux/rcupdate.h | 21 +++++++++--- include/linux/rcupreempt.h | 4 +-- include/linux/rcutree.h | 8 +++-- kernel/rcupreempt.c | 8 ++--- kernel/rcutree.c | 80 ++++++++++++++++++++++++++++----------------- kernel/rcutree.h | 4 +-- kernel/rcutree_trace.c | 20 ++++++------ kernel/sched.c | 2 +- kernel/softirq.c | 4 +-- 10 files changed, 95 insertions(+), 63 deletions(-) (limited to 'Documentation') diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt index 02cced183b2..187bbf10c92 100644 --- a/Documentation/RCU/trace.txt +++ b/Documentation/RCU/trace.txt @@ -191,8 +191,7 @@ rcu/rcuhier (which displays the struct rcu_node hierarchy). The output of "cat rcu/rcudata" looks as follows: -rcu: -rcu: +rcu_sched: 0 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=10951/1 dn=0 df=1101 of=0 ri=36 ql=0 b=10 1 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=16117/1 dn=0 df=1015 of=0 ri=0 ql=0 b=10 2 c=17829 g=17829 pq=1 pqc=17829 qp=0 dt=1445/1 dn=0 df=1839 of=0 ri=0 ql=0 b=10 @@ -306,7 +305,7 @@ comma-separated-variable spreadsheet format. The output of "cat rcu/rcugp" looks as follows: -rcu: completed=33062 gpnum=33063 +rcu_sched: completed=33062 gpnum=33063 rcu_bh: completed=464 gpnum=464 Again, this output is for both "rcu" and "rcu_bh". The fields are @@ -413,7 +412,7 @@ o Each element of the form "1/1 0:127 ^0" represents one struct The output of "cat rcu/rcu_pending" looks as follows: -rcu: +rcu_sched: 0 np=255892 qsp=53936 cbr=0 cng=14417 gpc=10033 gps=24320 nf=6445 nn=146741 1 np=261224 qsp=54638 cbr=0 cng=25723 gpc=16310 gps=2849 nf=5912 nn=155792 2 np=237496 qsp=49664 cbr=0 cng=2762 gpc=45478 gps=1762 nf=1201 nn=136629 diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 3c89d6a2591..e920f0fd59d 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -157,17 +157,28 @@ extern int rcu_scheduler_active; * - call_rcu_sched() and rcu_barrier_sched() * on the write-side to insure proper synchronization. */ -#define rcu_read_lock_sched() preempt_disable() -#define rcu_read_lock_sched_notrace() preempt_disable_notrace() +static inline void rcu_read_lock_sched(void) +{ + preempt_disable(); +} +static inline void rcu_read_lock_sched_notrace(void) +{ + preempt_disable_notrace(); +} /* * rcu_read_unlock_sched - marks the end of a RCU-classic critical section * * See rcu_read_lock_sched for more information. */ -#define rcu_read_unlock_sched() preempt_enable() -#define rcu_read_unlock_sched_notrace() preempt_enable_notrace() - +static inline void rcu_read_unlock_sched(void) +{ + preempt_enable(); +} +static inline void rcu_read_unlock_sched_notrace(void) +{ + preempt_enable_notrace(); +} /** diff --git a/include/linux/rcupreempt.h b/include/linux/rcupreempt.h index f164ac9b780..2963f080e48 100644 --- a/include/linux/rcupreempt.h +++ b/include/linux/rcupreempt.h @@ -40,8 +40,8 @@ #include #include -extern void rcu_qsctr_inc(int cpu); -static inline void rcu_bh_qsctr_inc(int cpu) { } +extern void rcu_sched_qs(int cpu); +static inline void rcu_bh_qs(int cpu) { } /* * Someone might want to pass call_rcu_bh as a function pointer. diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index e37d5e2a835..a0852d0d915 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -30,8 +30,8 @@ #ifndef __LINUX_RCUTREE_H #define __LINUX_RCUTREE_H -extern void rcu_qsctr_inc(int cpu); -extern void rcu_bh_qsctr_inc(int cpu); +extern void rcu_sched_qs(int cpu); +extern void rcu_bh_qs(int cpu); extern int rcu_pending(int cpu); extern int rcu_needs_cpu(int cpu); @@ -73,7 +73,8 @@ static inline void __rcu_read_unlock_bh(void) #define __synchronize_sched() synchronize_rcu() -#define call_rcu_sched(head, func) call_rcu(head, func) +extern void call_rcu_sched(struct rcu_head *head, + void (*func)(struct rcu_head *rcu)); static inline void synchronize_rcu_expedited(void) { @@ -91,6 +92,7 @@ extern void rcu_restart_cpu(int cpu); extern long rcu_batches_completed(void); extern long rcu_batches_completed_bh(void); +extern long rcu_batches_completed_sched(void); static inline void rcu_init_sched(void) { diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c index 510898a7bd6..7d777c9f394 100644 --- a/kernel/rcupreempt.c +++ b/kernel/rcupreempt.c @@ -159,7 +159,7 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(struct rcu_dyntick_sched, rcu_dyntick_sched .dynticks = 1, }; -void rcu_qsctr_inc(int cpu) +void rcu_sched_qs(int cpu) { struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu); @@ -967,12 +967,12 @@ void rcu_check_callbacks(int cpu, int user) * If this CPU took its interrupt from user mode or from the * idle loop, and this is not a nested interrupt, then * this CPU has to have exited all prior preept-disable - * sections of code. So increment the counter to note this. + * sections of code. So invoke rcu_sched_qs() to note this. * * The memory barrier is needed to handle the case where * writes from a preempt-disable section of code get reordered * into schedule() by this CPU's write buffer. So the memory - * barrier makes sure that the rcu_qsctr_inc() is seen by other + * barrier makes sure that the rcu_sched_qs() is seen by other * CPUs to happen after any such write. */ @@ -980,7 +980,7 @@ void rcu_check_callbacks(int cpu, int user) (idle_cpu(cpu) && !in_softirq() && hardirq_count() <= (1 << HARDIRQ_SHIFT))) { smp_mb(); /* Guard against aggressive schedule(). */ - rcu_qsctr_inc(cpu); + rcu_sched_qs(cpu); } rcu_check_mb(cpu); diff --git a/kernel/rcutree.c b/kernel/rcutree.c index a162f859dd3..4d71d4e8b5a 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -74,26 +74,25 @@ EXPORT_SYMBOL_GPL(rcu_lock_map); .n_force_qs_ngp = 0, \ } -struct rcu_state rcu_state = RCU_STATE_INITIALIZER(rcu_state); -DEFINE_PER_CPU(struct rcu_data, rcu_data); +struct rcu_state rcu_sched_state = RCU_STATE_INITIALIZER(rcu_sched_state); +DEFINE_PER_CPU(struct rcu_data, rcu_sched_data); struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh_state); DEFINE_PER_CPU(struct rcu_data, rcu_bh_data); /* - * Increment the quiescent state counter. - * The counter is a bit degenerated: We do not need to know + * Note a quiescent state. Because we do not need to know * how many quiescent states passed, just if there was at least - * one since the start of the grace period. Thus just a flag. + * one since the start of the grace period, this just sets a flag. */ -void rcu_qsctr_inc(int cpu) +void rcu_sched_qs(int cpu) { - struct rcu_data *rdp = &per_cpu(rcu_data, cpu); + struct rcu_data *rdp = &per_cpu(rcu_sched_data, cpu); rdp->passed_quiesc = 1; rdp->passed_quiesc_completed = rdp->completed; } -void rcu_bh_qsctr_inc(int cpu) +void rcu_bh_qs(int cpu) { struct rcu_data *rdp = &per_cpu(rcu_bh_data, cpu); rdp->passed_quiesc = 1; @@ -113,12 +112,22 @@ static int qlowmark = 100; /* Once only this many pending, use blimit. */ static void force_quiescent_state(struct rcu_state *rsp, int relaxed); +/* + * Return the number of RCU-sched batches processed thus far for debug & stats. + */ +long rcu_batches_completed_sched(void) +{ + return rcu_sched_state.completed; +} +EXPORT_SYMBOL_GPL(rcu_batches_completed_sched); + /* * Return the number of RCU batches processed thus far for debug & stats. + * @@@ placeholder, maps to rcu_batches_completed_sched(). */ long rcu_batches_completed(void) { - return rcu_state.completed; + return rcu_batches_completed_sched(); } EXPORT_SYMBOL_GPL(rcu_batches_completed); @@ -310,7 +319,7 @@ void rcu_irq_exit(void) WARN_ON_RATELIMIT(rdtp->dynticks & 0x1, &rcu_rs); /* If the interrupt queued a callback, get out of dyntick mode. */ - if (__get_cpu_var(rcu_data).nxtlist || + if (__get_cpu_var(rcu_sched_data).nxtlist || __get_cpu_var(rcu_bh_data).nxtlist) set_need_resched(); } @@ -847,7 +856,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) /* * Move callbacks from the outgoing CPU to the running CPU. * Note that the outgoing CPU is now quiscent, so it is now - * (uncharacteristically) safe to access it rcu_data structure. + * (uncharacteristically) safe to access its rcu_data structure. * Note also that we must carefully retain the order of the * outgoing CPU's callbacks in order for rcu_barrier() to work * correctly. Finally, note that we start all the callbacks @@ -878,7 +887,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp) */ static void rcu_offline_cpu(int cpu) { - __rcu_offline_cpu(cpu, &rcu_state); + __rcu_offline_cpu(cpu, &rcu_sched_state); __rcu_offline_cpu(cpu, &rcu_bh_state); } @@ -973,17 +982,16 @@ void rcu_check_callbacks(int cpu, int user) * Get here if this CPU took its interrupt from user * mode or from the idle loop, and if this is not a * nested interrupt. In this case, the CPU is in - * a quiescent state, so count it. + * a quiescent state, so note it. * * No memory barrier is required here because both - * rcu_qsctr_inc() and rcu_bh_qsctr_inc() reference - * only CPU-local variables that other CPUs neither - * access nor modify, at least not while the corresponding - * CPU is online. + * rcu_sched_qs() and rcu_bh_qs() reference only CPU-local + * variables that other CPUs neither access nor modify, + * at least not while the corresponding CPU is online. */ - rcu_qsctr_inc(cpu); - rcu_bh_qsctr_inc(cpu); + rcu_sched_qs(cpu); + rcu_bh_qs(cpu); } else if (!in_softirq()) { @@ -991,10 +999,10 @@ void rcu_check_callbacks(int cpu, int user) * Get here if this CPU did not take its interrupt from * softirq, in other words, if it is not interrupting * a rcu_bh read-side critical section. This is an _bh - * critical section, so count it. + * critical section, so note it. */ - rcu_bh_qsctr_inc(cpu); + rcu_bh_qs(cpu); } raise_softirq(RCU_SOFTIRQ); } @@ -1174,7 +1182,8 @@ static void rcu_process_callbacks(struct softirq_action *unused) */ smp_mb(); /* See above block comment. */ - __rcu_process_callbacks(&rcu_state, &__get_cpu_var(rcu_data)); + __rcu_process_callbacks(&rcu_sched_state, + &__get_cpu_var(rcu_sched_data)); __rcu_process_callbacks(&rcu_bh_state, &__get_cpu_var(rcu_bh_data)); /* @@ -1231,14 +1240,25 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu), } /* - * Queue an RCU callback for invocation after a grace period. + * Queue an RCU-sched callback for invocation after a grace period. + */ +void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) +{ + __call_rcu(head, func, &rcu_sched_state); +} +EXPORT_SYMBOL_GPL(call_rcu_sched); + +/* + * @@@ Queue an RCU callback for invocation after a grace period. + * @@@ Placeholder pending rcutree_plugin.h. */ void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) { - __call_rcu(head, func, &rcu_state); + call_rcu_sched(head, func); } EXPORT_SYMBOL_GPL(call_rcu); + /* * Queue an RCU for invocation after a quicker grace period. */ @@ -1311,7 +1331,7 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp) */ int rcu_pending(int cpu) { - return __rcu_pending(&rcu_state, &per_cpu(rcu_data, cpu)) || + return __rcu_pending(&rcu_sched_state, &per_cpu(rcu_sched_data, cpu)) || __rcu_pending(&rcu_bh_state, &per_cpu(rcu_bh_data, cpu)); } @@ -1324,7 +1344,7 @@ int rcu_pending(int cpu) int rcu_needs_cpu(int cpu) { /* RCU callbacks either ready or pending? */ - return per_cpu(rcu_data, cpu).nxtlist || + return per_cpu(rcu_sched_data, cpu).nxtlist || per_cpu(rcu_bh_data, cpu).nxtlist; } @@ -1418,7 +1438,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp) static void __cpuinit rcu_online_cpu(int cpu) { - rcu_init_percpu_data(cpu, &rcu_state); + rcu_init_percpu_data(cpu, &rcu_sched_state); rcu_init_percpu_data(cpu, &rcu_bh_state); } @@ -1545,10 +1565,10 @@ void __init __rcu_init(void) #ifdef CONFIG_RCU_CPU_STALL_DETECTOR printk(KERN_INFO "RCU-based detection of stalled CPUs is enabled.\n"); #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ - rcu_init_one(&rcu_state); - RCU_DATA_PTR_INIT(&rcu_state, rcu_data); + rcu_init_one(&rcu_sched_state); + RCU_DATA_PTR_INIT(&rcu_sched_state, rcu_sched_data); for_each_possible_cpu(i) - rcu_boot_init_percpu_data(i, &rcu_state); + rcu_boot_init_percpu_data(i, &rcu_sched_state); rcu_init_one(&rcu_bh_state); RCU_DATA_PTR_INIT(&rcu_bh_state, rcu_bh_data); for_each_possible_cpu(i) diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 7cc830a1c44..0024e5ddcc6 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -238,8 +238,8 @@ struct rcu_state { /* * RCU implementation internal declarations: */ -extern struct rcu_state rcu_state; -DECLARE_PER_CPU(struct rcu_data, rcu_data); +extern struct rcu_state rcu_sched_state; +DECLARE_PER_CPU(struct rcu_data, rcu_sched_data); extern struct rcu_state rcu_bh_state; DECLARE_PER_CPU(struct rcu_data, rcu_bh_data); diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c index 0cb52b88775..236c0504fee 100644 --- a/kernel/rcutree_trace.c +++ b/kernel/rcutree_trace.c @@ -77,8 +77,8 @@ static void print_one_rcu_data(struct seq_file *m, struct rcu_data *rdp) static int show_rcudata(struct seq_file *m, void *unused) { - seq_puts(m, "rcu:\n"); - PRINT_RCU_DATA(rcu_data, print_one_rcu_data, m); + seq_puts(m, "rcu_sched:\n"); + PRINT_RCU_DATA(rcu_sched_data, print_one_rcu_data, m); seq_puts(m, "rcu_bh:\n"); PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data, m); return 0; @@ -125,8 +125,8 @@ static int show_rcudata_csv(struct seq_file *m, void *unused) seq_puts(m, "\"dt\",\"dt nesting\",\"dn\",\"df\","); #endif /* #ifdef CONFIG_NO_HZ */ seq_puts(m, "\"of\",\"ri\",\"ql\",\"b\"\n"); - seq_puts(m, "\"rcu:\"\n"); - PRINT_RCU_DATA(rcu_data, print_one_rcu_data_csv, m); + seq_puts(m, "\"rcu_sched:\"\n"); + PRINT_RCU_DATA(rcu_sched_data, print_one_rcu_data_csv, m); seq_puts(m, "\"rcu_bh:\"\n"); PRINT_RCU_DATA(rcu_bh_data, print_one_rcu_data_csv, m); return 0; @@ -172,8 +172,8 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp) static int show_rcuhier(struct seq_file *m, void *unused) { - seq_puts(m, "rcu:\n"); - print_one_rcu_state(m, &rcu_state); + seq_puts(m, "rcu_sched:\n"); + print_one_rcu_state(m, &rcu_sched_state); seq_puts(m, "rcu_bh:\n"); print_one_rcu_state(m, &rcu_bh_state); return 0; @@ -194,8 +194,8 @@ static struct file_operations rcuhier_fops = { static int show_rcugp(struct seq_file *m, void *unused) { - seq_printf(m, "rcu: completed=%ld gpnum=%ld\n", - rcu_state.completed, rcu_state.gpnum); + seq_printf(m, "rcu_sched: completed=%ld gpnum=%ld\n", + rcu_sched_state.completed, rcu_sched_state.gpnum); seq_printf(m, "rcu_bh: completed=%ld gpnum=%ld\n", rcu_bh_state.completed, rcu_bh_state.gpnum); return 0; @@ -244,8 +244,8 @@ static void print_rcu_pendings(struct seq_file *m, struct rcu_state *rsp) static int show_rcu_pending(struct seq_file *m, void *unused) { - seq_puts(m, "rcu:\n"); - print_rcu_pendings(m, &rcu_state); + seq_puts(m, "rcu_sched:\n"); + print_rcu_pendings(m, &rcu_sched_state); seq_puts(m, "rcu_bh:\n"); print_rcu_pendings(m, &rcu_bh_state); return 0; diff --git a/kernel/sched.c b/kernel/sched.c index cda8b81f880..c9beca67a53 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -5325,7 +5325,7 @@ need_resched: preempt_disable(); cpu = smp_processor_id(); rq = cpu_rq(cpu); - rcu_qsctr_inc(cpu); + rcu_sched_qs(cpu); prev = rq->curr; switch_count = &prev->nivcsw; diff --git a/kernel/softirq.c b/kernel/softirq.c index eb5e131a048..7db25067cd2 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -227,7 +227,7 @@ restart: preempt_count() = prev_count; } - rcu_bh_qsctr_inc(cpu); + rcu_bh_qs(cpu); } h++; pending >>= 1; @@ -721,7 +721,7 @@ static int ksoftirqd(void * __bind_cpu) preempt_enable_no_resched(); cond_resched(); preempt_disable(); - rcu_qsctr_inc((long)__bind_cpu); + rcu_sched_qs((long)__bind_cpu); } preempt_enable(); set_current_state(TASK_INTERRUPTIBLE); -- cgit v1.2.3-70-g09d2 From 6b3ef48adf847f7adf11c870e3ffacac150f1564 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Sat, 22 Aug 2009 13:56:53 -0700 Subject: rcu: Remove CONFIG_PREEMPT_RCU Now that CONFIG_TREE_PREEMPT_RCU is in place, there is no further need for CONFIG_PREEMPT_RCU. Remove it, along with whatever subtle bugs it may (or may not) contain. Signed-off-by: Paul E. McKenney Cc: laijs@cn.fujitsu.com Cc: dipankar@in.ibm.com Cc: akpm@linux-foundation.org Cc: mathieu.desnoyers@polymtl.ca Cc: josht@linux.vnet.ibm.com Cc: dvhltc@us.ibm.com Cc: niv@us.ibm.com Cc: peterz@infradead.org Cc: rostedt@goodmis.org LKML-Reference: <125097461396-git-send-email-> Signed-off-by: Ingo Molnar --- Documentation/RCU/rcu.txt | 10 +- Documentation/RCU/whatisRCU.txt | 8 +- include/linux/init_task.h | 6 +- include/linux/rcupdate.h | 4 +- include/linux/rcupreempt.h | 140 ---- include/linux/rcupreempt_trace.h | 97 --- include/linux/sched.h | 13 - init/Kconfig | 20 +- kernel/Makefile | 2 - kernel/rcupreempt.c | 1518 -------------------------------------- kernel/rcupreempt_trace.c | 335 --------- lib/Kconfig.debug | 2 +- 12 files changed, 13 insertions(+), 2142 deletions(-) delete mode 100644 include/linux/rcupreempt.h delete mode 100644 include/linux/rcupreempt_trace.h delete mode 100644 kernel/rcupreempt.c delete mode 100644 kernel/rcupreempt_trace.c (limited to 'Documentation') diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt index 7aa2002ade7..2a23523ce47 100644 --- a/Documentation/RCU/rcu.txt +++ b/Documentation/RCU/rcu.txt @@ -36,7 +36,7 @@ o How can the updater tell when a grace period has completed executed in user mode, or executed in the idle loop, we can safely free up that item. - Preemptible variants of RCU (CONFIG_PREEMPT_RCU) get the + Preemptible variants of RCU (CONFIG_TREE_PREEMPT_RCU) get the same effect, but require that the readers manipulate CPU-local counters. These counters allow limited types of blocking within RCU read-side critical sections. SRCU also uses @@ -79,10 +79,10 @@ o I hear that RCU is patented? What is with that? o I hear that RCU needs work in order to support realtime kernels? This work is largely completed. Realtime-friendly RCU can be - enabled via the CONFIG_PREEMPT_RCU kernel configuration parameter. - However, work is in progress for enabling priority boosting of - preempted RCU read-side critical sections. This is needed if you - have CPU-bound realtime threads. + enabled via the CONFIG_TREE_PREEMPT_RCU kernel configuration + parameter. However, work is in progress for enabling priority + boosting of preempted RCU read-side critical sections. This is + needed if you have CPU-bound realtime threads. o Where can I find more information on RCU? diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt index 97ded2432c5..e41a7fecf0d 100644 --- a/Documentation/RCU/whatisRCU.txt +++ b/Documentation/RCU/whatisRCU.txt @@ -136,10 +136,10 @@ rcu_read_lock() Used by a reader to inform the reclaimer that the reader is entering an RCU read-side critical section. It is illegal to block while in an RCU read-side critical section, though - kernels built with CONFIG_PREEMPT_RCU can preempt RCU read-side - critical sections. Any RCU-protected data structure accessed - during an RCU read-side critical section is guaranteed to remain - unreclaimed for the full duration of that critical section. + kernels built with CONFIG_TREE_PREEMPT_RCU can preempt RCU + read-side critical sections. Any RCU-protected data structure + accessed during an RCU read-side critical section is guaranteed to + remain unreclaimed for the full duration of that critical section. Reference counts may be used in conjunction with RCU to maintain longer-term references to data structures. diff --git a/include/linux/init_task.h b/include/linux/init_task.h index 971a968831b..79d4baee31b 100644 --- a/include/linux/init_task.h +++ b/include/linux/init_task.h @@ -94,11 +94,7 @@ extern struct group_info init_groups; # define CAP_INIT_BSET CAP_INIT_EFF_SET #endif -#ifdef CONFIG_PREEMPT_RCU -#define INIT_TASK_RCU_PREEMPT(tsk) \ - .rcu_read_lock_nesting = 0, \ - .rcu_flipctr_idx = 0, -#elif defined(CONFIG_TREE_PREEMPT_RCU) +#ifdef CONFIG_TREE_PREEMPT_RCU #define INIT_TASK_RCU_PREEMPT(tsk) \ .rcu_read_lock_nesting = 0, \ .rcu_read_unlock_special = 0, \ diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 26892f5e7bd..ec90fc34fea 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -68,11 +68,9 @@ extern int rcu_scheduler_active; #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) #include -#elif defined(CONFIG_PREEMPT_RCU) -#include #else #error "Unknown RCU implementation specified to kernel configuration" -#endif /* #else #if defined(CONFIG_CLASSIC_RCU) */ +#endif #define RCU_HEAD_INIT { .next = NULL, .func = NULL } #define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT diff --git a/include/linux/rcupreempt.h b/include/linux/rcupreempt.h deleted file mode 100644 index a42ab88e921..00000000000 --- a/include/linux/rcupreempt.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion (RT implementation) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) IBM Corporation, 2006 - * - * Author: Paul McKenney - * - * Based on the original work by Paul McKenney - * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. - * Papers: - * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf - * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) - * - * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU - * - */ - -#ifndef __LINUX_RCUPREEMPT_H -#define __LINUX_RCUPREEMPT_H - -#include -#include -#include -#include -#include -#include - -extern void rcu_sched_qs(int cpu); -static inline void rcu_bh_qs(int cpu) { } - -/* - * Someone might want to pass call_rcu_bh as a function pointer. - * So this needs to just be a rename and not a macro function. - * (no parentheses) - */ -#define call_rcu_bh call_rcu - -/** - * call_rcu_sched - Queue RCU callback for invocation after sched grace period. - * @head: structure to be used for queueing the RCU updates. - * @func: actual update function to be invoked after the grace period - * - * The update function will be invoked some time after a full - * synchronize_sched()-style grace period elapses, in other words after - * all currently executing preempt-disabled sections of code (including - * hardirq handlers, NMI handlers, and local_irq_save() blocks) have - * completed. - */ -extern void call_rcu_sched(struct rcu_head *head, - void (*func)(struct rcu_head *head)); - -extern void __rcu_read_lock(void); -extern void __rcu_read_unlock(void); -extern int rcu_needs_cpu(int cpu); - -#define __rcu_read_lock_bh() { rcu_read_lock(); local_bh_disable(); } -#define __rcu_read_unlock_bh() { local_bh_enable(); rcu_read_unlock(); } - -extern void __synchronize_sched(void); - -static inline void synchronize_rcu_expedited(void) -{ - synchronize_rcu(); /* Placeholder for new rcupreempt implementation. */ -} - -static inline void synchronize_rcu_bh_expedited(void) -{ - synchronize_rcu_bh(); /* Placeholder for new rcupreempt impl. */ -} - -extern void __rcu_init(void); -extern void rcu_init_sched(void); -extern void rcu_check_callbacks(int cpu, int user); -extern void rcu_restart_cpu(int cpu); -extern long rcu_batches_completed(void); - -/* - * Return the number of RCU batches processed thus far. Useful for debug - * and statistic. The _bh variant is identifcal to straight RCU - */ -static inline long rcu_batches_completed_bh(void) -{ - return rcu_batches_completed(); -} - -static inline void exit_rcu(void) -{ -} - -#ifdef CONFIG_RCU_TRACE -struct rcupreempt_trace; -extern long *rcupreempt_flipctr(int cpu); -extern long rcupreempt_data_completed(void); -extern int rcupreempt_flip_flag(int cpu); -extern int rcupreempt_mb_flag(int cpu); -extern char *rcupreempt_try_flip_state_name(void); -extern struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu); -#endif - -struct softirq_action; - -#ifdef CONFIG_NO_HZ -extern void rcu_enter_nohz(void); -extern void rcu_exit_nohz(void); -#else -# define rcu_enter_nohz() do { } while (0) -# define rcu_exit_nohz() do { } while (0) -#endif - -/* - * A context switch is a grace period for rcupreempt synchronize_rcu() - * only during early boot, before the scheduler has been initialized. - * So, how the heck do we get a context switch? Well, if the caller - * invokes synchronize_rcu(), they are willing to accept a context - * switch, so we simply pretend that one happened. - * - * After boot, there might be a blocked or preempted task in an RCU - * read-side critical section, so we cannot then take the fastpath. - */ -static inline int rcu_blocking_is_gp(void) -{ - return num_online_cpus() == 1 && !rcu_scheduler_active; -} - -#endif /* __LINUX_RCUPREEMPT_H */ diff --git a/include/linux/rcupreempt_trace.h b/include/linux/rcupreempt_trace.h deleted file mode 100644 index b99ae073192..00000000000 --- a/include/linux/rcupreempt_trace.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion (RT implementation) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) IBM Corporation, 2006 - * - * Author: Paul McKenney - * - * Based on the original work by Paul McKenney - * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. - * Papers: - * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf - * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) - * - * For detailed explanation of the Preemptible Read-Copy Update mechanism see - - * http://lwn.net/Articles/253651/ - */ - -#ifndef __LINUX_RCUPREEMPT_TRACE_H -#define __LINUX_RCUPREEMPT_TRACE_H - -#include -#include - -#include - -/* - * PREEMPT_RCU data structures. - */ - -struct rcupreempt_trace { - long next_length; - long next_add; - long wait_length; - long wait_add; - long done_length; - long done_add; - long done_remove; - atomic_t done_invoked; - long rcu_check_callbacks; - atomic_t rcu_try_flip_1; - atomic_t rcu_try_flip_e1; - long rcu_try_flip_i1; - long rcu_try_flip_ie1; - long rcu_try_flip_g1; - long rcu_try_flip_a1; - long rcu_try_flip_ae1; - long rcu_try_flip_a2; - long rcu_try_flip_z1; - long rcu_try_flip_ze1; - long rcu_try_flip_z2; - long rcu_try_flip_m1; - long rcu_try_flip_me1; - long rcu_try_flip_m2; -}; - -#ifdef CONFIG_RCU_TRACE -#define RCU_TRACE(fn, arg) fn(arg); -#else -#define RCU_TRACE(fn, arg) -#endif - -extern void rcupreempt_trace_move2done(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_i1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_ie1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_g1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_a1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_ae1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_a2(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_z1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_ze1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_z2(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_m1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_me1(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_try_flip_m2(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_invoke(struct rcupreempt_trace *trace); -extern void rcupreempt_trace_next_add(struct rcupreempt_trace *trace); - -#endif /* __LINUX_RCUPREEMPT_TRACE_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index d7f98f637a2..bfca26d63b1 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1205,11 +1205,6 @@ struct task_struct { unsigned int policy; cpumask_t cpus_allowed; -#ifdef CONFIG_PREEMPT_RCU - int rcu_read_lock_nesting; - int rcu_flipctr_idx; -#endif /* #ifdef CONFIG_PREEMPT_RCU */ - #ifdef CONFIG_TREE_PREEMPT_RCU int rcu_read_lock_nesting; char rcu_read_unlock_special; @@ -1744,14 +1739,6 @@ static inline void rcu_copy_process(struct task_struct *p) INIT_LIST_HEAD(&p->rcu_node_entry); } -#elif defined(CONFIG_PREEMPT_RCU) - -static inline void rcu_copy_process(struct task_struct *p) -{ - p->rcu_read_lock_nesting = 0; - p->rcu_flipctr_idx = 0; -} - #else static inline void rcu_copy_process(struct task_struct *p) diff --git a/init/Kconfig b/init/Kconfig index f88da2d1c1f..8e8b76d8a27 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -324,17 +324,6 @@ config TREE_RCU thousands of CPUs. It also scales down nicely to smaller systems. -config PREEMPT_RCU - bool "Preemptible RCU" - depends on PREEMPT - help - This option reduces the latency of the kernel by making certain - RCU sections preemptible. Normally RCU code is non-preemptible, if - this option is selected then read-only RCU sections become - preemptible. This helps latency, but may expose bugs due to - now-naive assumptions about each RCU read-side critical section - remaining on a given CPU through its execution. - config TREE_PREEMPT_RCU bool "Preemptable tree-based hierarchical RCU" depends on PREEMPT @@ -348,7 +337,7 @@ endchoice config RCU_TRACE bool "Enable tracing for RCU" - depends on TREE_RCU || PREEMPT_RCU || TREE_PREEMPT_RCU + depends on TREE_RCU || TREE_PREEMPT_RCU help This option provides tracing in RCU which presents stats in debugfs for debugging RCU implementation. @@ -395,13 +384,6 @@ config TREE_RCU_TRACE TREE_PREEMPT_RCU implementations, permitting Makefile to trivially select kernel/rcutree_trace.c. -config PREEMPT_RCU_TRACE - def_bool RCU_TRACE && PREEMPT_RCU - select DEBUG_FS - help - This option provides tracing for the PREEMPT_RCU implementation, - permitting Makefile to trivially select kernel/rcupreempt_trace.c. - endmenu # "RCU Subsystem" config IKCONFIG diff --git a/kernel/Makefile b/kernel/Makefile index 1a38b4789dd..b833bd5cc12 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -82,9 +82,7 @@ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o obj-$(CONFIG_TREE_RCU) += rcutree.o obj-$(CONFIG_TREE_PREEMPT_RCU) += rcutree.o -obj-$(CONFIG_PREEMPT_RCU) += rcupreempt.o obj-$(CONFIG_TREE_RCU_TRACE) += rcutree_trace.o -obj-$(CONFIG_PREEMPT_RCU_TRACE) += rcupreempt_trace.o obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_SYSCTL) += utsname_sysctl.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o diff --git a/kernel/rcupreempt.c b/kernel/rcupreempt.c deleted file mode 100644 index 0053ce56e32..00000000000 --- a/kernel/rcupreempt.c +++ /dev/null @@ -1,1518 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion, realtime implementation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright IBM Corporation, 2006 - * - * Authors: Paul E. McKenney - * With thanks to Esben Nielsen, Bill Huey, and Ingo Molnar - * for pushing me away from locks and towards counters, and - * to Suparna Bhattacharya for pushing me completely away - * from atomic instructions on the read side. - * - * - Added handling of Dynamic Ticks - * Copyright 2007 - Paul E. Mckenney - * - Steven Rostedt - * - * Papers: http://www.rdrop.com/users/paulmck/RCU - * - * Design Document: http://lwn.net/Articles/253651/ - * - * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU/ *.txt - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * PREEMPT_RCU data structures. - */ - -/* - * GP_STAGES specifies the number of times the state machine has - * to go through the all the rcu_try_flip_states (see below) - * in a single Grace Period. - * - * GP in GP_STAGES stands for Grace Period ;) - */ -#define GP_STAGES 2 -struct rcu_data { - spinlock_t lock; /* Protect rcu_data fields. */ - long completed; /* Number of last completed batch. */ - int waitlistcount; - struct rcu_head *nextlist; - struct rcu_head **nexttail; - struct rcu_head *waitlist[GP_STAGES]; - struct rcu_head **waittail[GP_STAGES]; - struct rcu_head *donelist; /* from waitlist & waitschedlist */ - struct rcu_head **donetail; - long rcu_flipctr[2]; - struct rcu_head *nextschedlist; - struct rcu_head **nextschedtail; - struct rcu_head *waitschedlist; - struct rcu_head **waitschedtail; - int rcu_sched_sleeping; -#ifdef CONFIG_RCU_TRACE - struct rcupreempt_trace trace; -#endif /* #ifdef CONFIG_RCU_TRACE */ -}; - -/* - * States for rcu_try_flip() and friends. - */ - -enum rcu_try_flip_states { - - /* - * Stay here if nothing is happening. Flip the counter if somthing - * starts happening. Denoted by "I" - */ - rcu_try_flip_idle_state, - - /* - * Wait here for all CPUs to notice that the counter has flipped. This - * prevents the old set of counters from ever being incremented once - * we leave this state, which in turn is necessary because we cannot - * test any individual counter for zero -- we can only check the sum. - * Denoted by "A". - */ - rcu_try_flip_waitack_state, - - /* - * Wait here for the sum of the old per-CPU counters to reach zero. - * Denoted by "Z". - */ - rcu_try_flip_waitzero_state, - - /* - * Wait here for each of the other CPUs to execute a memory barrier. - * This is necessary to ensure that these other CPUs really have - * completed executing their RCU read-side critical sections, despite - * their CPUs wildly reordering memory. Denoted by "M". - */ - rcu_try_flip_waitmb_state, -}; - -/* - * States for rcu_ctrlblk.rcu_sched_sleep. - */ - -enum rcu_sched_sleep_states { - rcu_sched_not_sleeping, /* Not sleeping, callbacks need GP. */ - rcu_sched_sleep_prep, /* Thinking of sleeping, rechecking. */ - rcu_sched_sleeping, /* Sleeping, awaken if GP needed. */ -}; - -struct rcu_ctrlblk { - spinlock_t fliplock; /* Protect state-machine transitions. */ - long completed; /* Number of last completed batch. */ - enum rcu_try_flip_states rcu_try_flip_state; /* The current state of - the rcu state machine */ - spinlock_t schedlock; /* Protect rcu_sched sleep state. */ - enum rcu_sched_sleep_states sched_sleep; /* rcu_sched state. */ - wait_queue_head_t sched_wq; /* Place for rcu_sched to sleep. */ -}; - -struct rcu_dyntick_sched { - int dynticks; - int dynticks_snap; - int sched_qs; - int sched_qs_snap; - int sched_dynticks_snap; -}; - -static DEFINE_PER_CPU_SHARED_ALIGNED(struct rcu_dyntick_sched, rcu_dyntick_sched) = { - .dynticks = 1, -}; - -static int rcu_pending(int cpu); - -void rcu_sched_qs(int cpu) -{ - struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu); - - rdssp->sched_qs++; -} - -#ifdef CONFIG_NO_HZ - -void rcu_enter_nohz(void) -{ - static DEFINE_RATELIMIT_STATE(rs, 10 * HZ, 1); - - smp_mb(); /* CPUs seeing ++ must see prior RCU read-side crit sects */ - __get_cpu_var(rcu_dyntick_sched).dynticks++; - WARN_ON_RATELIMIT(__get_cpu_var(rcu_dyntick_sched).dynticks & 0x1, &rs); -} - -void rcu_exit_nohz(void) -{ - static DEFINE_RATELIMIT_STATE(rs, 10 * HZ, 1); - - __get_cpu_var(rcu_dyntick_sched).dynticks++; - smp_mb(); /* CPUs seeing ++ must see later RCU read-side crit sects */ - WARN_ON_RATELIMIT(!(__get_cpu_var(rcu_dyntick_sched).dynticks & 0x1), - &rs); -} - -#endif /* CONFIG_NO_HZ */ - - -static DEFINE_PER_CPU(struct rcu_data, rcu_data); - -static struct rcu_ctrlblk rcu_ctrlblk = { - .fliplock = __SPIN_LOCK_UNLOCKED(rcu_ctrlblk.fliplock), - .completed = 0, - .rcu_try_flip_state = rcu_try_flip_idle_state, - .schedlock = __SPIN_LOCK_UNLOCKED(rcu_ctrlblk.schedlock), - .sched_sleep = rcu_sched_not_sleeping, - .sched_wq = __WAIT_QUEUE_HEAD_INITIALIZER(rcu_ctrlblk.sched_wq), -}; - -static struct task_struct *rcu_sched_grace_period_task; - -#ifdef CONFIG_RCU_TRACE -static char *rcu_try_flip_state_names[] = - { "idle", "waitack", "waitzero", "waitmb" }; -#endif /* #ifdef CONFIG_RCU_TRACE */ - -static DECLARE_BITMAP(rcu_cpu_online_map, NR_CPUS) __read_mostly - = CPU_BITS_NONE; - -/* - * Enum and per-CPU flag to determine when each CPU has seen - * the most recent counter flip. - */ - -enum rcu_flip_flag_values { - rcu_flip_seen, /* Steady/initial state, last flip seen. */ - /* Only GP detector can update. */ - rcu_flipped /* Flip just completed, need confirmation. */ - /* Only corresponding CPU can update. */ -}; -static DEFINE_PER_CPU_SHARED_ALIGNED(enum rcu_flip_flag_values, rcu_flip_flag) - = rcu_flip_seen; - -/* - * Enum and per-CPU flag to determine when each CPU has executed the - * needed memory barrier to fence in memory references from its last RCU - * read-side critical section in the just-completed grace period. - */ - -enum rcu_mb_flag_values { - rcu_mb_done, /* Steady/initial state, no mb()s required. */ - /* Only GP detector can update. */ - rcu_mb_needed /* Flip just completed, need an mb(). */ - /* Only corresponding CPU can update. */ -}; -static DEFINE_PER_CPU_SHARED_ALIGNED(enum rcu_mb_flag_values, rcu_mb_flag) - = rcu_mb_done; - -/* - * RCU_DATA_ME: find the current CPU's rcu_data structure. - * RCU_DATA_CPU: find the specified CPU's rcu_data structure. - */ -#define RCU_DATA_ME() (&__get_cpu_var(rcu_data)) -#define RCU_DATA_CPU(cpu) (&per_cpu(rcu_data, cpu)) - -/* - * Helper macro for tracing when the appropriate rcu_data is not - * cached in a local variable, but where the CPU number is so cached. - */ -#define RCU_TRACE_CPU(f, cpu) RCU_TRACE(f, &(RCU_DATA_CPU(cpu)->trace)); - -/* - * Helper macro for tracing when the appropriate rcu_data is not - * cached in a local variable. - */ -#define RCU_TRACE_ME(f) RCU_TRACE(f, &(RCU_DATA_ME()->trace)); - -/* - * Helper macro for tracing when the appropriate rcu_data is pointed - * to by a local variable. - */ -#define RCU_TRACE_RDP(f, rdp) RCU_TRACE(f, &((rdp)->trace)); - -#define RCU_SCHED_BATCH_TIME (HZ / 50) - -/* - * Return the number of RCU batches processed thus far. Useful - * for debug and statistics. - */ -long rcu_batches_completed(void) -{ - return rcu_ctrlblk.completed; -} -EXPORT_SYMBOL_GPL(rcu_batches_completed); - -void __rcu_read_lock(void) -{ - int idx; - struct task_struct *t = current; - int nesting; - - nesting = ACCESS_ONCE(t->rcu_read_lock_nesting); - if (nesting != 0) { - - /* An earlier rcu_read_lock() covers us, just count it. */ - - t->rcu_read_lock_nesting = nesting + 1; - - } else { - unsigned long flags; - - /* - * We disable interrupts for the following reasons: - * - If we get scheduling clock interrupt here, and we - * end up acking the counter flip, it's like a promise - * that we will never increment the old counter again. - * Thus we will break that promise if that - * scheduling clock interrupt happens between the time - * we pick the .completed field and the time that we - * increment our counter. - * - * - We don't want to be preempted out here. - * - * NMIs can still occur, of course, and might themselves - * contain rcu_read_lock(). - */ - - local_irq_save(flags); - - /* - * Outermost nesting of rcu_read_lock(), so increment - * the current counter for the current CPU. Use volatile - * casts to prevent the compiler from reordering. - */ - - idx = ACCESS_ONCE(rcu_ctrlblk.completed) & 0x1; - ACCESS_ONCE(RCU_DATA_ME()->rcu_flipctr[idx])++; - - /* - * Now that the per-CPU counter has been incremented, we - * are protected from races with rcu_read_lock() invoked - * from NMI handlers on this CPU. We can therefore safely - * increment the nesting counter, relieving further NMIs - * of the need to increment the per-CPU counter. - */ - - ACCESS_ONCE(t->rcu_read_lock_nesting) = nesting + 1; - - /* - * Now that we have preventing any NMIs from storing - * to the ->rcu_flipctr_idx, we can safely use it to - * remember which counter to decrement in the matching - * rcu_read_unlock(). - */ - - ACCESS_ONCE(t->rcu_flipctr_idx) = idx; - local_irq_restore(flags); - } -} -EXPORT_SYMBOL_GPL(__rcu_read_lock); - -void __rcu_read_unlock(void) -{ - int idx; - struct task_struct *t = current; - int nesting; - - nesting = ACCESS_ONCE(t->rcu_read_lock_nesting); - if (nesting > 1) { - - /* - * We are still protected by the enclosing rcu_read_lock(), - * so simply decrement the counter. - */ - - t->rcu_read_lock_nesting = nesting - 1; - - } else { - unsigned long flags; - - /* - * Disable local interrupts to prevent the grace-period - * detection state machine from seeing us half-done. - * NMIs can still occur, of course, and might themselves - * contain rcu_read_lock() and rcu_read_unlock(). - */ - - local_irq_save(flags); - - /* - * Outermost nesting of rcu_read_unlock(), so we must - * decrement the current counter for the current CPU. - * This must be done carefully, because NMIs can - * occur at any point in this code, and any rcu_read_lock() - * and rcu_read_unlock() pairs in the NMI handlers - * must interact non-destructively with this code. - * Lots of volatile casts, and -very- careful ordering. - * - * Changes to this code, including this one, must be - * inspected, validated, and tested extremely carefully!!! - */ - - /* - * First, pick up the index. - */ - - idx = ACCESS_ONCE(t->rcu_flipctr_idx); - - /* - * Now that we have fetched the counter index, it is - * safe to decrement the per-task RCU nesting counter. - * After this, any interrupts or NMIs will increment and - * decrement the per-CPU counters. - */ - ACCESS_ONCE(t->rcu_read_lock_nesting) = nesting - 1; - - /* - * It is now safe to decrement this task's nesting count. - * NMIs that occur after this statement will route their - * rcu_read_lock() calls through this "else" clause, and - * will thus start incrementing the per-CPU counter on - * their own. They will also clobber ->rcu_flipctr_idx, - * but that is OK, since we have already fetched it. - */ - - ACCESS_ONCE(RCU_DATA_ME()->rcu_flipctr[idx])--; - local_irq_restore(flags); - } -} -EXPORT_SYMBOL_GPL(__rcu_read_unlock); - -/* - * If a global counter flip has occurred since the last time that we - * advanced callbacks, advance them. Hardware interrupts must be - * disabled when calling this function. - */ -static void __rcu_advance_callbacks(struct rcu_data *rdp) -{ - int cpu; - int i; - int wlc = 0; - - if (rdp->completed != rcu_ctrlblk.completed) { - if (rdp->waitlist[GP_STAGES - 1] != NULL) { - *rdp->donetail = rdp->waitlist[GP_STAGES - 1]; - rdp->donetail = rdp->waittail[GP_STAGES - 1]; - RCU_TRACE_RDP(rcupreempt_trace_move2done, rdp); - } - for (i = GP_STAGES - 2; i >= 0; i--) { - if (rdp->waitlist[i] != NULL) { - rdp->waitlist[i + 1] = rdp->waitlist[i]; - rdp->waittail[i + 1] = rdp->waittail[i]; - wlc++; - } else { - rdp->waitlist[i + 1] = NULL; - rdp->waittail[i + 1] = - &rdp->waitlist[i + 1]; - } - } - if (rdp->nextlist != NULL) { - rdp->waitlist[0] = rdp->nextlist; - rdp->waittail[0] = rdp->nexttail; - wlc++; - rdp->nextlist = NULL; - rdp->nexttail = &rdp->nextlist; - RCU_TRACE_RDP(rcupreempt_trace_move2wait, rdp); - } else { - rdp->waitlist[0] = NULL; - rdp->waittail[0] = &rdp->waitlist[0]; - } - rdp->waitlistcount = wlc; - rdp->completed = rcu_ctrlblk.completed; - } - - /* - * Check to see if this CPU needs to report that it has seen - * the most recent counter flip, thereby declaring that all - * subsequent rcu_read_lock() invocations will respect this flip. - */ - - cpu = raw_smp_processor_id(); - if (per_cpu(rcu_flip_flag, cpu) == rcu_flipped) { - smp_mb(); /* Subsequent counter accesses must see new value */ - per_cpu(rcu_flip_flag, cpu) = rcu_flip_seen; - smp_mb(); /* Subsequent RCU read-side critical sections */ - /* seen -after- acknowledgement. */ - } -} - -#ifdef CONFIG_NO_HZ -static DEFINE_PER_CPU(int, rcu_update_flag); - -/** - * rcu_irq_enter - Called from Hard irq handlers and NMI/SMI. - * - * If the CPU was idle with dynamic ticks active, this updates the - * rcu_dyntick_sched.dynticks to let the RCU handling know that the - * CPU is active. - */ -void rcu_irq_enter(void) -{ - int cpu = smp_processor_id(); - struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu); - - if (per_cpu(rcu_update_flag, cpu)) - per_cpu(rcu_update_flag, cpu)++; - - /* - * Only update if we are coming from a stopped ticks mode - * (rcu_dyntick_sched.dynticks is even). - */ - if (!in_interrupt() && - (rdssp->dynticks & 0x1) == 0) { - /* - * The following might seem like we could have a race - * with NMI/SMIs. But this really isn't a problem. - * Here we do a read/modify/write, and the race happens - * when an NMI/SMI comes in after the read and before - * the write. But NMI/SMIs will increment this counter - * twice before returning, so the zero bit will not - * be corrupted by the NMI/SMI which is the most important - * part. - * - * The only thing is that we would bring back the counter - * to a postion that it was in during the NMI/SMI. - * But the zero bit would be set, so the rest of the - * counter would again be ignored. - * - * On return from the IRQ, the counter may have the zero - * bit be 0 and the counter the same as the return from - * the NMI/SMI. If the state machine was so unlucky to - * see that, it still doesn't matter, since all - * RCU read-side critical sections on this CPU would - * have already completed. - */ - rdssp->dynticks++; - /* - * The following memory barrier ensures that any - * rcu_read_lock() primitives in the irq handler - * are seen by other CPUs to follow the above - * increment to rcu_dyntick_sched.dynticks. This is - * required in order for other CPUs to correctly - * determine when it is safe to advance the RCU - * grace-period state machine. - */ - smp_mb(); /* see above block comment. */ - /* - * Since we can't determine the dynamic tick mode from - * the rcu_dyntick_sched.dynticks after this routine, - * we use a second flag to acknowledge that we came - * from an idle state with ticks stopped. - */ - per_cpu(rcu_update_flag, cpu)++; - /* - * If we take an NMI/SMI now, they will also increment - * the rcu_update_flag, and will not update the - * rcu_dyntick_sched.dynticks on exit. That is for - * this IRQ to do. - */ - } -} - -/** - * rcu_irq_exit - Called from exiting Hard irq context. - * - * If the CPU was idle with dynamic ticks active, update the - * rcu_dyntick_sched.dynticks to let the RCU handling be - * aware that the CPU is going back to idle with no ticks. - */ -void rcu_irq_exit(void) -{ - int cpu = smp_processor_id(); - struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu); - - /* - * rcu_update_flag is set if we interrupted the CPU - * when it was idle with ticks stopped. - * Once this occurs, we keep track of interrupt nesting - * because a NMI/SMI could also come in, and we still - * only want the IRQ that started the increment of the - * rcu_dyntick_sched.dynticks to be the one that modifies - * it on exit. - */ - if (per_cpu(rcu_update_flag, cpu)) { - if (--per_cpu(rcu_update_flag, cpu)) - return; - - /* This must match the interrupt nesting */ - WARN_ON(in_interrupt()); - - /* - * If an NMI/SMI happens now we are still - * protected by the rcu_dyntick_sched.dynticks being odd. - */ - - /* - * The following memory barrier ensures that any - * rcu_read_unlock() primitives in the irq handler - * are seen by other CPUs to preceed the following - * increment to rcu_dyntick_sched.dynticks. This - * is required in order for other CPUs to determine - * when it is safe to advance the RCU grace-period - * state machine. - */ - smp_mb(); /* see above block comment. */ - rdssp->dynticks++; - WARN_ON(rdssp->dynticks & 0x1); - } -} - -void rcu_nmi_enter(void) -{ - rcu_irq_enter(); -} - -void rcu_nmi_exit(void) -{ - rcu_irq_exit(); -} - -static void dyntick_save_progress_counter(int cpu) -{ - struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu); - - rdssp->dynticks_snap = rdssp->dynticks; -} - -static inline int -rcu_try_flip_waitack_needed(int cpu) -{ - long curr; - long snap; - struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu); - - curr = rdssp->dynticks; - snap = rdssp->dynticks_snap; - smp_mb(); /* force ordering with cpu entering/leaving dynticks. */ - - /* - * If the CPU remained in dynticks mode for the entire time - * and didn't take any interrupts, NMIs, SMIs, or whatever, - * then it cannot be in the middle of an rcu_read_lock(), so - * the next rcu_read_lock() it executes must use the new value - * of the counter. So we can safely pretend that this CPU - * already acknowledged the counter. - */ - - if ((curr == snap) && ((curr & 0x1) == 0)) - return 0; - - /* - * If the CPU passed through or entered a dynticks idle phase with - * no active irq handlers, then, as above, we can safely pretend - * that this CPU already acknowledged the counter. - */ - - if ((curr - snap) > 2 || (curr & 0x1) == 0) - return 0; - - /* We need this CPU to explicitly acknowledge the counter flip. */ - - return 1; -} - -static inline int -rcu_try_flip_waitmb_needed(int cpu) -{ - long curr; - long snap; - struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu); - - curr = rdssp->dynticks; - snap = rdssp->dynticks_snap; - smp_mb(); /* force ordering with cpu entering/leaving dynticks. */ - - /* - * If the CPU remained in dynticks mode for the entire time - * and didn't take any interrupts, NMIs, SMIs, or whatever, - * then it cannot have executed an RCU read-side critical section - * during that time, so there is no need for it to execute a - * memory barrier. - */ - - if ((curr == snap) && ((curr & 0x1) == 0)) - return 0; - - /* - * If the CPU either entered or exited an outermost interrupt, - * SMI, NMI, or whatever handler, then we know that it executed - * a memory barrier when doing so. So we don't need another one. - */ - if (curr != snap) - return 0; - - /* We need the CPU to execute a memory barrier. */ - - return 1; -} - -static void dyntick_save_progress_counter_sched(int cpu) -{ - struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu); - - rdssp->sched_dynticks_snap = rdssp->dynticks; -} - -static int rcu_qsctr_inc_needed_dyntick(int cpu) -{ - long curr; - long snap; - struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu); - - curr = rdssp->dynticks; - snap = rdssp->sched_dynticks_snap; - smp_mb(); /* force ordering with cpu entering/leaving dynticks. */ - - /* - * If the CPU remained in dynticks mode for the entire time - * and didn't take any interrupts, NMIs, SMIs, or whatever, - * then it cannot be in the middle of an rcu_read_lock(), so - * the next rcu_read_lock() it executes must use the new value - * of the counter. Therefore, this CPU has been in a quiescent - * state the entire time, and we don't need to wait for it. - */ - - if ((curr == snap) && ((curr & 0x1) == 0)) - return 0; - - /* - * If the CPU passed through or entered a dynticks idle phase with - * no active irq handlers, then, as above, this CPU has already - * passed through a quiescent state. - */ - - if ((curr - snap) > 2 || (snap & 0x1) == 0) - return 0; - - /* We need this CPU to go through a quiescent state. */ - - return 1; -} - -#else /* !CONFIG_NO_HZ */ - -# define dyntick_save_progress_counter(cpu) do { } while (0) -# define rcu_try_flip_waitack_needed(cpu) (1) -# define rcu_try_flip_waitmb_needed(cpu) (1) - -# define dyntick_save_progress_counter_sched(cpu) do { } while (0) -# define rcu_qsctr_inc_needed_dyntick(cpu) (1) - -#endif /* CONFIG_NO_HZ */ - -static void save_qsctr_sched(int cpu) -{ - struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu); - - rdssp->sched_qs_snap = rdssp->sched_qs; -} - -static inline int rcu_qsctr_inc_needed(int cpu) -{ - struct rcu_dyntick_sched *rdssp = &per_cpu(rcu_dyntick_sched, cpu); - - /* - * If there has been a quiescent state, no more need to wait - * on this CPU. - */ - - if (rdssp->sched_qs != rdssp->sched_qs_snap) { - smp_mb(); /* force ordering with cpu entering schedule(). */ - return 0; - } - - /* We need this CPU to go through a quiescent state. */ - - return 1; -} - -/* - * Get here when RCU is idle. Decide whether we need to - * move out of idle state, and return non-zero if so. - * "Straightforward" approach for the moment, might later - * use callback-list lengths, grace-period duration, or - * some such to determine when to exit idle state. - * Might also need a pre-idle test that does not acquire - * the lock, but let's get the simple case working first... - */ - -static int -rcu_try_flip_idle(void) -{ - int cpu; - - RCU_TRACE_ME(rcupreempt_trace_try_flip_i1); - if (!rcu_pending(smp_processor_id())) { - RCU_TRACE_ME(rcupreempt_trace_try_flip_ie1); - return 0; - } - - /* - * Do the flip. - */ - - RCU_TRACE_ME(rcupreempt_trace_try_flip_g1); - rcu_ctrlblk.completed++; /* stands in for rcu_try_flip_g2 */ - - /* - * Need a memory barrier so that other CPUs see the new - * counter value before they see the subsequent change of all - * the rcu_flip_flag instances to rcu_flipped. - */ - - smp_mb(); /* see above block comment. */ - - /* Now ask each CPU for acknowledgement of the flip. */ - - for_each_cpu(cpu, to_cpumask(rcu_cpu_online_map)) { - per_cpu(rcu_flip_flag, cpu) = rcu_flipped; - dyntick_save_progress_counter(cpu); - } - - return 1; -} - -/* - * Wait for CPUs to acknowledge the flip. - */ - -static int -rcu_try_flip_waitack(void) -{ - int cpu; - - RCU_TRACE_ME(rcupreempt_trace_try_flip_a1); - for_each_cpu(cpu, to_cpumask(rcu_cpu_online_map)) - if (rcu_try_flip_waitack_needed(cpu) && - per_cpu(rcu_flip_flag, cpu) != rcu_flip_seen) { - RCU_TRACE_ME(rcupreempt_trace_try_flip_ae1); - return 0; - } - - /* - * Make sure our checks above don't bleed into subsequent - * waiting for the sum of the counters to reach zero. - */ - - smp_mb(); /* see above block comment. */ - RCU_TRACE_ME(rcupreempt_trace_try_flip_a2); - return 1; -} - -/* - * Wait for collective ``last'' counter to reach zero, - * then tell all CPUs to do an end-of-grace-period memory barrier. - */ - -static int -rcu_try_flip_waitzero(void) -{ - int cpu; - int lastidx = !(rcu_ctrlblk.completed & 0x1); - int sum = 0; - - /* Check to see if the sum of the "last" counters is zero. */ - - RCU_TRACE_ME(rcupreempt_trace_try_flip_z1); - for_each_possible_cpu(cpu) - sum += RCU_DATA_CPU(cpu)->rcu_flipctr[lastidx]; - if (sum != 0) { - RCU_TRACE_ME(rcupreempt_trace_try_flip_ze1); - return 0; - } - - /* - * This ensures that the other CPUs see the call for - * memory barriers -after- the sum to zero has been - * detected here - */ - smp_mb(); /* ^^^^^^^^^^^^ */ - - /* Call for a memory barrier from each CPU. */ - for_each_cpu(cpu, to_cpumask(rcu_cpu_online_map)) { - per_cpu(rcu_mb_flag, cpu) = rcu_mb_needed; - dyntick_save_progress_counter(cpu); - } - - RCU_TRACE_ME(rcupreempt_trace_try_flip_z2); - return 1; -} - -/* - * Wait for all CPUs to do their end-of-grace-period memory barrier. - * Return 0 once all CPUs have done so. - */ - -static int -rcu_try_flip_waitmb(void) -{ - int cpu; - - RCU_TRACE_ME(rcupreempt_trace_try_flip_m1); - for_each_cpu(cpu, to_cpumask(rcu_cpu_online_map)) - if (rcu_try_flip_waitmb_needed(cpu) && - per_cpu(rcu_mb_flag, cpu) != rcu_mb_done) { - RCU_TRACE_ME(rcupreempt_trace_try_flip_me1); - return 0; - } - - smp_mb(); /* Ensure that the above checks precede any following flip. */ - RCU_TRACE_ME(rcupreempt_trace_try_flip_m2); - return 1; -} - -/* - * Attempt a single flip of the counters. Remember, a single flip does - * -not- constitute a grace period. Instead, the interval between - * at least GP_STAGES consecutive flips is a grace period. - * - * If anyone is nuts enough to run this CONFIG_PREEMPT_RCU implementation - * on a large SMP, they might want to use a hierarchical organization of - * the per-CPU-counter pairs. - */ -static void rcu_try_flip(void) -{ - unsigned long flags; - - RCU_TRACE_ME(rcupreempt_trace_try_flip_1); - if (unlikely(!spin_trylock_irqsave(&rcu_ctrlblk.fliplock, flags))) { - RCU_TRACE_ME(rcupreempt_trace_try_flip_e1); - return; - } - - /* - * Take the next transition(s) through the RCU grace-period - * flip-counter state machine. - */ - - switch (rcu_ctrlblk.rcu_try_flip_state) { - case rcu_try_flip_idle_state: - if (rcu_try_flip_idle()) - rcu_ctrlblk.rcu_try_flip_state = - rcu_try_flip_waitack_state; - break; - case rcu_try_flip_waitack_state: - if (rcu_try_flip_waitack()) - rcu_ctrlblk.rcu_try_flip_state = - rcu_try_flip_waitzero_state; - break; - case rcu_try_flip_waitzero_state: - if (rcu_try_flip_waitzero()) - rcu_ctrlblk.rcu_try_flip_state = - rcu_try_flip_waitmb_state; - break; - case rcu_try_flip_waitmb_state: - if (rcu_try_flip_waitmb()) - rcu_ctrlblk.rcu_try_flip_state = - rcu_try_flip_idle_state; - } - spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags); -} - -/* - * Check to see if this CPU needs to do a memory barrier in order to - * ensure that any prior RCU read-side critical sections have committed - * their counter manipulations and critical-section memory references - * before declaring the grace period to be completed. - */ -static void rcu_check_mb(int cpu) -{ - if (per_cpu(rcu_mb_flag, cpu) == rcu_mb_needed) { - smp_mb(); /* Ensure RCU read-side accesses are visible. */ - per_cpu(rcu_mb_flag, cpu) = rcu_mb_done; - } -} - -void rcu_check_callbacks(int cpu, int user) -{ - unsigned long flags; - struct rcu_data *rdp; - - if (!rcu_pending(cpu)) - return; /* if nothing for RCU to do. */ - - /* - * If this CPU took its interrupt from user mode or from the - * idle loop, and this is not a nested interrupt, then - * this CPU has to have exited all prior preept-disable - * sections of code. So invoke rcu_sched_qs() to note this. - * - * The memory barrier is needed to handle the case where - * writes from a preempt-disable section of code get reordered - * into schedule() by this CPU's write buffer. So the memory - * barrier makes sure that the rcu_sched_qs() is seen by other - * CPUs to happen after any such write. - */ - - rdp = RCU_DATA_CPU(cpu); - if (user || - (idle_cpu(cpu) && !in_softirq() && - hardirq_count() <= (1 << HARDIRQ_SHIFT))) { - smp_mb(); /* Guard against aggressive schedule(). */ - rcu_sched_qs(cpu); - } - - rcu_check_mb(cpu); - if (rcu_ctrlblk.completed == rdp->completed) - rcu_try_flip(); - spin_lock_irqsave(&rdp->lock, flags); - RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp); - __rcu_advance_callbacks(rdp); - if (rdp->donelist == NULL) { - spin_unlock_irqrestore(&rdp->lock, flags); - } else { - spin_unlock_irqrestore(&rdp->lock, flags); - raise_softirq(RCU_SOFTIRQ); - } -} - -/* - * Needed by dynticks, to make sure all RCU processing has finished - * when we go idle: - */ -void rcu_advance_callbacks(int cpu, int user) -{ - unsigned long flags; - struct rcu_data *rdp = RCU_DATA_CPU(cpu); - - if (rcu_ctrlblk.completed == rdp->completed) { - rcu_try_flip(); - if (rcu_ctrlblk.completed == rdp->completed) - return; - } - spin_lock_irqsave(&rdp->lock, flags); - RCU_TRACE_RDP(rcupreempt_trace_check_callbacks, rdp); - __rcu_advance_callbacks(rdp); - spin_unlock_irqrestore(&rdp->lock, flags); -} - -#ifdef CONFIG_HOTPLUG_CPU -#define rcu_offline_cpu_enqueue(srclist, srctail, dstlist, dsttail) do { \ - *dsttail = srclist; \ - if (srclist != NULL) { \ - dsttail = srctail; \ - srclist = NULL; \ - srctail = &srclist;\ - } \ - } while (0) - -void rcu_offline_cpu(int cpu) -{ - int i; - struct rcu_head *list = NULL; - unsigned long flags; - struct rcu_data *rdp = RCU_DATA_CPU(cpu); - struct rcu_head *schedlist = NULL; - struct rcu_head **schedtail = &schedlist; - struct rcu_head **tail = &list; - - /* - * Remove all callbacks from the newly dead CPU, retaining order. - * Otherwise rcu_barrier() will fail - */ - - spin_lock_irqsave(&rdp->lock, flags); - rcu_offline_cpu_enqueue(rdp->donelist, rdp->donetail, list, tail); - for (i = GP_STAGES - 1; i >= 0; i--) - rcu_offline_cpu_enqueue(rdp->waitlist[i], rdp->waittail[i], - list, tail); - rcu_offline_cpu_enqueue(rdp->nextlist, rdp->nexttail, list, tail); - rcu_offline_cpu_enqueue(rdp->waitschedlist, rdp->waitschedtail, - schedlist, schedtail); - rcu_offline_cpu_enqueue(rdp->nextschedlist, rdp->nextschedtail, - schedlist, schedtail); - rdp->rcu_sched_sleeping = 0; - spin_unlock_irqrestore(&rdp->lock, flags); - rdp->waitlistcount = 0; - - /* Disengage the newly dead CPU from the grace-period computation. */ - - spin_lock_irqsave(&rcu_ctrlblk.fliplock, flags); - rcu_check_mb(cpu); - if (per_cpu(rcu_flip_flag, cpu) == rcu_flipped) { - smp_mb(); /* Subsequent counter accesses must see new value */ - per_cpu(rcu_flip_flag, cpu) = rcu_flip_seen; - smp_mb(); /* Subsequent RCU read-side critical sections */ - /* seen -after- acknowledgement. */ - } - - cpumask_clear_cpu(cpu, to_cpumask(rcu_cpu_online_map)); - - spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags); - - /* - * Place the removed callbacks on the current CPU's queue. - * Make them all start a new grace period: simple approach, - * in theory could starve a given set of callbacks, but - * you would need to be doing some serious CPU hotplugging - * to make this happen. If this becomes a problem, adding - * a synchronize_rcu() to the hotplug path would be a simple - * fix. - */ - - local_irq_save(flags); /* disable preempt till we know what lock. */ - rdp = RCU_DATA_ME(); - spin_lock(&rdp->lock); - *rdp->nexttail = list; - if (list) - rdp->nexttail = tail; - *rdp->nextschedtail = schedlist; - if (schedlist) - rdp->nextschedtail = schedtail; - spin_unlock_irqrestore(&rdp->lock, flags); -} - -#else /* #ifdef CONFIG_HOTPLUG_CPU */ - -void rcu_offline_cpu(int cpu) -{ -} - -#endif /* #else #ifdef CONFIG_HOTPLUG_CPU */ - -void __cpuinit rcu_online_cpu(int cpu) -{ - unsigned long flags; - struct rcu_data *rdp; - - spin_lock_irqsave(&rcu_ctrlblk.fliplock, flags); - cpumask_set_cpu(cpu, to_cpumask(rcu_cpu_online_map)); - spin_unlock_irqrestore(&rcu_ctrlblk.fliplock, flags); - - /* - * The rcu_sched grace-period processing might have bypassed - * this CPU, given that it was not in the rcu_cpu_online_map - * when the grace-period scan started. This means that the - * grace-period task might sleep. So make sure that if this - * should happen, the first callback posted to this CPU will - * wake up the grace-period task if need be. - */ - - rdp = RCU_DATA_CPU(cpu); - spin_lock_irqsave(&rdp->lock, flags); - rdp->rcu_sched_sleeping = 1; - spin_unlock_irqrestore(&rdp->lock, flags); -} - -static void rcu_process_callbacks(struct softirq_action *unused) -{ - unsigned long flags; - struct rcu_head *next, *list; - struct rcu_data *rdp; - - local_irq_save(flags); - rdp = RCU_DATA_ME(); - spin_lock(&rdp->lock); - list = rdp->donelist; - if (list == NULL) { - spin_unlock_irqrestore(&rdp->lock, flags); - return; - } - rdp->donelist = NULL; - rdp->donetail = &rdp->donelist; - RCU_TRACE_RDP(rcupreempt_trace_done_remove, rdp); - spin_unlock_irqrestore(&rdp->lock, flags); - while (list) { - next = list->next; - list->func(list); - list = next; - RCU_TRACE_ME(rcupreempt_trace_invoke); - } -} - -void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) -{ - unsigned long flags; - struct rcu_data *rdp; - - head->func = func; - head->next = NULL; - local_irq_save(flags); - rdp = RCU_DATA_ME(); - spin_lock(&rdp->lock); - __rcu_advance_callbacks(rdp); - *rdp->nexttail = head; - rdp->nexttail = &head->next; - RCU_TRACE_RDP(rcupreempt_trace_next_add, rdp); - spin_unlock_irqrestore(&rdp->lock, flags); -} -EXPORT_SYMBOL_GPL(call_rcu); - -void call_rcu_sched(struct rcu_head *head, void (*func)(struct rcu_head *rcu)) -{ - unsigned long flags; - struct rcu_data *rdp; - int wake_gp = 0; - - head->func = func; - head->next = NULL; - local_irq_save(flags); - rdp = RCU_DATA_ME(); - spin_lock(&rdp->lock); - *rdp->nextschedtail = head; - rdp->nextschedtail = &head->next; - if (rdp->rcu_sched_sleeping) { - - /* Grace-period processing might be sleeping... */ - - rdp->rcu_sched_sleeping = 0; - wake_gp = 1; - } - spin_unlock_irqrestore(&rdp->lock, flags); - if (wake_gp) { - - /* Wake up grace-period processing, unless someone beat us. */ - - spin_lock_irqsave(&rcu_ctrlblk.schedlock, flags); - if (rcu_ctrlblk.sched_sleep != rcu_sched_sleeping) - wake_gp = 0; - rcu_ctrlblk.sched_sleep = rcu_sched_not_sleeping; - spin_unlock_irqrestore(&rcu_ctrlblk.schedlock, flags); - if (wake_gp) - wake_up_interruptible(&rcu_ctrlblk.sched_wq); - } -} -EXPORT_SYMBOL_GPL(call_rcu_sched); - -/* - * Wait until all currently running preempt_disable() code segments - * (including hardware-irq-disable segments) complete. Note that - * in -rt this does -not- necessarily result in all currently executing - * interrupt -handlers- having completed. - */ -void __synchronize_sched(void) -{ - struct rcu_synchronize rcu; - - if (num_online_cpus() == 1) - return; /* blocking is gp if only one CPU! */ - - init_completion(&rcu.completion); - /* Will wake me after RCU finished. */ - call_rcu_sched(&rcu.head, wakeme_after_rcu); - /* Wait for it. */ - wait_for_completion(&rcu.completion); -} -EXPORT_SYMBOL_GPL(__synchronize_sched); - -/* - * kthread function that manages call_rcu_sched grace periods. - */ -static int rcu_sched_grace_period(void *arg) -{ - int couldsleep; /* might sleep after current pass. */ - int couldsleepnext = 0; /* might sleep after next pass. */ - int cpu; - unsigned long flags; - struct rcu_data *rdp; - int ret; - - /* - * Each pass through the following loop handles one - * rcu_sched grace period cycle. - */ - do { - /* Save each CPU's current state. */ - - for_each_online_cpu(cpu) { - dyntick_save_progress_counter_sched(cpu); - save_qsctr_sched(cpu); - } - - /* - * Sleep for about an RCU grace-period's worth to - * allow better batching and to consume less CPU. - */ - schedule_timeout_interruptible(RCU_SCHED_BATCH_TIME); - - /* - * If there was nothing to do last time, prepare to - * sleep at the end of the current grace period cycle. - */ - couldsleep = couldsleepnext; - couldsleepnext = 1; - if (couldsleep) { - spin_lock_irqsave(&rcu_ctrlblk.schedlock, flags); - rcu_ctrlblk.sched_sleep = rcu_sched_sleep_prep; - spin_unlock_irqrestore(&rcu_ctrlblk.schedlock, flags); - } - - /* - * Wait on each CPU in turn to have either visited - * a quiescent state or been in dynticks-idle mode. - */ - for_each_online_cpu(cpu) { - while (rcu_qsctr_inc_needed(cpu) && - rcu_qsctr_inc_needed_dyntick(cpu)) { - /* resched_cpu(cpu); @@@ */ - schedule_timeout_interruptible(1); - } - } - - /* Advance callbacks for each CPU. */ - - for_each_online_cpu(cpu) { - - rdp = RCU_DATA_CPU(cpu); - spin_lock_irqsave(&rdp->lock, flags); - - /* - * We are running on this CPU irq-disabled, so no - * CPU can go offline until we re-enable irqs. - * The current CPU might have already gone - * offline (between the for_each_offline_cpu and - * the spin_lock_irqsave), but in that case all its - * callback lists will be empty, so no harm done. - * - * Advance the callbacks! We share normal RCU's - * donelist, since callbacks are invoked the - * same way in either case. - */ - if (rdp->waitschedlist != NULL) { - *rdp->donetail = rdp->waitschedlist; - rdp->donetail = rdp->waitschedtail; - - /* - * Next rcu_check_callbacks() will - * do the required raise_softirq(). - */ - } - if (rdp->nextschedlist != NULL) { - rdp->waitschedlist = rdp->nextschedlist; - rdp->waitschedtail = rdp->nextschedtail; - couldsleep = 0; - couldsleepnext = 0; - } else { - rdp->waitschedlist = NULL; - rdp->waitschedtail = &rdp->waitschedlist; - } - rdp->nextschedlist = NULL; - rdp->nextschedtail = &rdp->nextschedlist; - - /* Mark sleep intention. */ - - rdp->rcu_sched_sleeping = couldsleep; - - spin_unlock_irqrestore(&rdp->lock, flags); - } - - /* If we saw callbacks on the last scan, go deal with them. */ - - if (!couldsleep) - continue; - - /* Attempt to block... */ - - spin_lock_irqsave(&rcu_ctrlblk.schedlock, flags); - if (rcu_ctrlblk.sched_sleep != rcu_sched_sleep_prep) { - - /* - * Someone posted a callback after we scanned. - * Go take care of it. - */ - spin_unlock_irqrestore(&rcu_ctrlblk.schedlock, flags); - couldsleepnext = 0; - continue; - } - - /* Block until the next person posts a callback. */ - - rcu_ctrlblk.sched_sleep = rcu_sched_sleeping; - spin_unlock_irqrestore(&rcu_ctrlblk.schedlock, flags); - ret = 0; /* unused */ - __wait_event_interruptible(rcu_ctrlblk.sched_wq, - rcu_ctrlblk.sched_sleep != rcu_sched_sleeping, - ret); - - couldsleepnext = 0; - - } while (!kthread_should_stop()); - - return (0); -} - -/* - * Check to see if any future RCU-related work will need to be done - * by the current CPU, even if none need be done immediately, returning - * 1 if so. Assumes that notifiers would take care of handling any - * outstanding requests from the RCU core. - * - * This function is part of the RCU implementation; it is -not- - * an exported member of the RCU API. - */ -int rcu_needs_cpu(int cpu) -{ - struct rcu_data *rdp = RCU_DATA_CPU(cpu); - - return (rdp->donelist != NULL || - !!rdp->waitlistcount || - rdp->nextlist != NULL || - rdp->nextschedlist != NULL || - rdp->waitschedlist != NULL); -} - -static int rcu_pending(int cpu) -{ - struct rcu_data *rdp = RCU_DATA_CPU(cpu); - - /* The CPU has at least one callback queued somewhere. */ - - if (rdp->donelist != NULL || - !!rdp->waitlistcount || - rdp->nextlist != NULL || - rdp->nextschedlist != NULL || - rdp->waitschedlist != NULL) - return 1; - - /* The RCU core needs an acknowledgement from this CPU. */ - - if ((per_cpu(rcu_flip_flag, cpu) == rcu_flipped) || - (per_cpu(rcu_mb_flag, cpu) == rcu_mb_needed)) - return 1; - - /* This CPU has fallen behind the global grace-period number. */ - - if (rdp->completed != rcu_ctrlblk.completed) - return 1; - - /* Nothing needed from this CPU. */ - - return 0; -} - -int __cpuinit rcu_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - long cpu = (long)hcpu; - - switch (action) { - case CPU_UP_PREPARE: - case CPU_UP_PREPARE_FROZEN: - rcu_online_cpu(cpu); - break; - case CPU_UP_CANCELED: - case CPU_UP_CANCELED_FROZEN: - case CPU_DEAD: - case CPU_DEAD_FROZEN: - rcu_offline_cpu(cpu); - break; - default: - break; - } - return NOTIFY_OK; -} - -void __init __rcu_init(void) -{ - int cpu; - int i; - struct rcu_data *rdp; - - printk(KERN_NOTICE "Preemptible RCU implementation.\n"); - for_each_possible_cpu(cpu) { - rdp = RCU_DATA_CPU(cpu); - spin_lock_init(&rdp->lock); - rdp->completed = 0; - rdp->waitlistcount = 0; - rdp->nextlist = NULL; - rdp->nexttail = &rdp->nextlist; - for (i = 0; i < GP_STAGES; i++) { - rdp->waitlist[i] = NULL; - rdp->waittail[i] = &rdp->waitlist[i]; - } - rdp->donelist = NULL; - rdp->donetail = &rdp->donelist; - rdp->rcu_flipctr[0] = 0; - rdp->rcu_flipctr[1] = 0; - rdp->nextschedlist = NULL; - rdp->nextschedtail = &rdp->nextschedlist; - rdp->waitschedlist = NULL; - rdp->waitschedtail = &rdp->waitschedlist; - rdp->rcu_sched_sleeping = 0; - } - open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); -} - -/* - * Late-boot-time RCU initialization that must wait until after scheduler - * has been initialized. - */ -void __init rcu_init_sched(void) -{ - rcu_sched_grace_period_task = kthread_run(rcu_sched_grace_period, - NULL, - "rcu_sched_grace_period"); - WARN_ON(IS_ERR(rcu_sched_grace_period_task)); -} - -#ifdef CONFIG_RCU_TRACE -long *rcupreempt_flipctr(int cpu) -{ - return &RCU_DATA_CPU(cpu)->rcu_flipctr[0]; -} -EXPORT_SYMBOL_GPL(rcupreempt_flipctr); - -int rcupreempt_flip_flag(int cpu) -{ - return per_cpu(rcu_flip_flag, cpu); -} -EXPORT_SYMBOL_GPL(rcupreempt_flip_flag); - -int rcupreempt_mb_flag(int cpu) -{ - return per_cpu(rcu_mb_flag, cpu); -} -EXPORT_SYMBOL_GPL(rcupreempt_mb_flag); - -char *rcupreempt_try_flip_state_name(void) -{ - return rcu_try_flip_state_names[rcu_ctrlblk.rcu_try_flip_state]; -} -EXPORT_SYMBOL_GPL(rcupreempt_try_flip_state_name); - -struct rcupreempt_trace *rcupreempt_trace_cpu(int cpu) -{ - struct rcu_data *rdp = RCU_DATA_CPU(cpu); - - return &rdp->trace; -} -EXPORT_SYMBOL_GPL(rcupreempt_trace_cpu); - -#endif /* #ifdef RCU_TRACE */ diff --git a/kernel/rcupreempt_trace.c b/kernel/rcupreempt_trace.c deleted file mode 100644 index 11640346a50..00000000000 --- a/kernel/rcupreempt_trace.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Read-Copy Update tracing for realtime implementation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright IBM Corporation, 2006 - * - * Papers: http://www.rdrop.com/users/paulmck/RCU - * - * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU/ *.txt - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct mutex rcupreempt_trace_mutex; -static char *rcupreempt_trace_buf; -#define RCUPREEMPT_TRACE_BUF_SIZE 4096 - -void rcupreempt_trace_move2done(struct rcupreempt_trace *trace) -{ - trace->done_length += trace->wait_length; - trace->done_add += trace->wait_length; - trace->wait_length = 0; -} -void rcupreempt_trace_move2wait(struct rcupreempt_trace *trace) -{ - trace->wait_length += trace->next_length; - trace->wait_add += trace->next_length; - trace->next_length = 0; -} -void rcupreempt_trace_try_flip_1(struct rcupreempt_trace *trace) -{ - atomic_inc(&trace->rcu_try_flip_1); -} -void rcupreempt_trace_try_flip_e1(struct rcupreempt_trace *trace) -{ - atomic_inc(&trace->rcu_try_flip_e1); -} -void rcupreempt_trace_try_flip_i1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_i1++; -} -void rcupreempt_trace_try_flip_ie1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_ie1++; -} -void rcupreempt_trace_try_flip_g1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_g1++; -} -void rcupreempt_trace_try_flip_a1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_a1++; -} -void rcupreempt_trace_try_flip_ae1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_ae1++; -} -void rcupreempt_trace_try_flip_a2(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_a2++; -} -void rcupreempt_trace_try_flip_z1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_z1++; -} -void rcupreempt_trace_try_flip_ze1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_ze1++; -} -void rcupreempt_trace_try_flip_z2(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_z2++; -} -void rcupreempt_trace_try_flip_m1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_m1++; -} -void rcupreempt_trace_try_flip_me1(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_me1++; -} -void rcupreempt_trace_try_flip_m2(struct rcupreempt_trace *trace) -{ - trace->rcu_try_flip_m2++; -} -void rcupreempt_trace_check_callbacks(struct rcupreempt_trace *trace) -{ - trace->rcu_check_callbacks++; -} -void rcupreempt_trace_done_remove(struct rcupreempt_trace *trace) -{ - trace->done_remove += trace->done_length; - trace->done_length = 0; -} -void rcupreempt_trace_invoke(struct rcupreempt_trace *trace) -{ - atomic_inc(&trace->done_invoked); -} -void rcupreempt_trace_next_add(struct rcupreempt_trace *trace) -{ - trace->next_add++; - trace->next_length++; -} - -static void rcupreempt_trace_sum(struct rcupreempt_trace *sp) -{ - struct rcupreempt_trace *cp; - int cpu; - - memset(sp, 0, sizeof(*sp)); - for_each_possible_cpu(cpu) { - cp = rcupreempt_trace_cpu(cpu); - sp->next_length += cp->next_length; - sp->next_add += cp->next_add; - sp->wait_length += cp->wait_length; - sp->wait_add += cp->wait_add; - sp->done_length += cp->done_length; - sp->done_add += cp->done_add; - sp->done_remove += cp->done_remove; - atomic_add(atomic_read(&cp->done_invoked), &sp->done_invoked); - sp->rcu_check_callbacks += cp->rcu_check_callbacks; - atomic_add(atomic_read(&cp->rcu_try_flip_1), - &sp->rcu_try_flip_1); - atomic_add(atomic_read(&cp->rcu_try_flip_e1), - &sp->rcu_try_flip_e1); - sp->rcu_try_flip_i1 += cp->rcu_try_flip_i1; - sp->rcu_try_flip_ie1 += cp->rcu_try_flip_ie1; - sp->rcu_try_flip_g1 += cp->rcu_try_flip_g1; - sp->rcu_try_flip_a1 += cp->rcu_try_flip_a1; - sp->rcu_try_flip_ae1 += cp->rcu_try_flip_ae1; - sp->rcu_try_flip_a2 += cp->rcu_try_flip_a2; - sp->rcu_try_flip_z1 += cp->rcu_try_flip_z1; - sp->rcu_try_flip_ze1 += cp->rcu_try_flip_ze1; - sp->rcu_try_flip_z2 += cp->rcu_try_flip_z2; - sp->rcu_try_flip_m1 += cp->rcu_try_flip_m1; - sp->rcu_try_flip_me1 += cp->rcu_try_flip_me1; - sp->rcu_try_flip_m2 += cp->rcu_try_flip_m2; - } -} - -static ssize_t rcustats_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct rcupreempt_trace trace; - ssize_t bcount; - int cnt = 0; - - rcupreempt_trace_sum(&trace); - mutex_lock(&rcupreempt_trace_mutex); - snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt, - "ggp=%ld rcc=%ld\n", - rcu_batches_completed(), - trace.rcu_check_callbacks); - snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE - cnt, - "na=%ld nl=%ld wa=%ld wl=%ld da=%ld dl=%ld dr=%ld di=%d\n" - "1=%d e1=%d i1=%ld ie1=%ld g1=%ld a1=%ld ae1=%ld a2=%ld\n" - "z1=%ld ze1=%ld z2=%ld m1=%ld me1=%ld m2=%ld\n", - - trace.next_add, trace.next_length, - trace.wait_add, trace.wait_length, - trace.done_add, trace.done_length, - trace.done_remove, atomic_read(&trace.done_invoked), - atomic_read(&trace.rcu_try_flip_1), - atomic_read(&trace.rcu_try_flip_e1), - trace.rcu_try_flip_i1, trace.rcu_try_flip_ie1, - trace.rcu_try_flip_g1, - trace.rcu_try_flip_a1, trace.rcu_try_flip_ae1, - trace.rcu_try_flip_a2, - trace.rcu_try_flip_z1, trace.rcu_try_flip_ze1, - trace.rcu_try_flip_z2, - trace.rcu_try_flip_m1, trace.rcu_try_flip_me1, - trace.rcu_try_flip_m2); - bcount = simple_read_from_buffer(buffer, count, ppos, - rcupreempt_trace_buf, strlen(rcupreempt_trace_buf)); - mutex_unlock(&rcupreempt_trace_mutex); - return bcount; -} - -static ssize_t rcugp_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - long oldgp = rcu_batches_completed(); - ssize_t bcount; - - mutex_lock(&rcupreempt_trace_mutex); - synchronize_rcu(); - snprintf(rcupreempt_trace_buf, RCUPREEMPT_TRACE_BUF_SIZE, - "oldggp=%ld newggp=%ld\n", oldgp, rcu_batches_completed()); - bcount = simple_read_from_buffer(buffer, count, ppos, - rcupreempt_trace_buf, strlen(rcupreempt_trace_buf)); - mutex_unlock(&rcupreempt_trace_mutex); - return bcount; -} - -static ssize_t rcuctrs_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - int cnt = 0; - int cpu; - int f = rcu_batches_completed() & 0x1; - ssize_t bcount; - - mutex_lock(&rcupreempt_trace_mutex); - - cnt += snprintf(&rcupreempt_trace_buf[cnt], RCUPREEMPT_TRACE_BUF_SIZE, - "CPU last cur F M\n"); - for_each_possible_cpu(cpu) { - long *flipctr = rcupreempt_flipctr(cpu); - cnt += snprintf(&rcupreempt_trace_buf[cnt], - RCUPREEMPT_TRACE_BUF_SIZE - cnt, - "%3d%c %4ld %3ld %d %d\n", - cpu, - cpu_is_offline(cpu) ? '!' : ' ', - flipctr[!f], - flipctr[f], - rcupreempt_flip_flag(cpu), - rcupreempt_mb_flag(cpu)); - } - cnt += snprintf(&rcupreempt_trace_buf[cnt], - RCUPREEMPT_TRACE_BUF_SIZE - cnt, - "ggp = %ld, state = %s\n", - rcu_batches_completed(), - rcupreempt_try_flip_state_name()); - cnt += snprintf(&rcupreempt_trace_buf[cnt], - RCUPREEMPT_TRACE_BUF_SIZE - cnt, - "\n"); - bcount = simple_read_from_buffer(buffer, count, ppos, - rcupreempt_trace_buf, strlen(rcupreempt_trace_buf)); - mutex_unlock(&rcupreempt_trace_mutex); - return bcount; -} - -static struct file_operations rcustats_fops = { - .owner = THIS_MODULE, - .read = rcustats_read, -}; - -static struct file_operations rcugp_fops = { - .owner = THIS_MODULE, - .read = rcugp_read, -}; - -static struct file_operations rcuctrs_fops = { - .owner = THIS_MODULE, - .read = rcuctrs_read, -}; - -static struct dentry *rcudir, *statdir, *ctrsdir, *gpdir; -static int rcupreempt_debugfs_init(void) -{ - rcudir = debugfs_create_dir("rcu", NULL); - if (!rcudir) - goto out; - statdir = debugfs_create_file("rcustats", 0444, rcudir, - NULL, &rcustats_fops); - if (!statdir) - goto free_out; - - gpdir = debugfs_create_file("rcugp", 0444, rcudir, NULL, &rcugp_fops); - if (!gpdir) - goto free_out; - - ctrsdir = debugfs_create_file("rcuctrs", 0444, rcudir, - NULL, &rcuctrs_fops); - if (!ctrsdir) - goto free_out; - return 0; -free_out: - if (statdir) - debugfs_remove(statdir); - if (gpdir) - debugfs_remove(gpdir); - debugfs_remove(rcudir); -out: - return 1; -} - -static int __init rcupreempt_trace_init(void) -{ - int ret; - - mutex_init(&rcupreempt_trace_mutex); - rcupreempt_trace_buf = kmalloc(RCUPREEMPT_TRACE_BUF_SIZE, GFP_KERNEL); - if (!rcupreempt_trace_buf) - return 1; - ret = rcupreempt_debugfs_init(); - if (ret) - kfree(rcupreempt_trace_buf); - return ret; -} - -static void __exit rcupreempt_trace_cleanup(void) -{ - debugfs_remove(statdir); - debugfs_remove(gpdir); - debugfs_remove(ctrsdir); - debugfs_remove(rcudir); - kfree(rcupreempt_trace_buf); -} - - -module_init(rcupreempt_trace_init); -module_exit(rcupreempt_trace_cleanup); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index f87fb0c8f92..82fbc49728d 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -725,7 +725,7 @@ config RCU_TORTURE_TEST_RUNNABLE config RCU_CPU_STALL_DETECTOR bool "Check for stalled CPUs delaying RCU grace periods" - depends on CLASSIC_RCU || TREE_RCU || TREE_PREEMPT_RCU + depends on TREE_RCU || TREE_PREEMPT_RCU default n help This option causes RCU to printk information on which -- cgit v1.2.3-70-g09d2 From e2e465693247b7f81e85aa8b1b482d9502812be4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Aug 2009 18:25:30 +0200 Subject: ALSA: hda - Add / fix model entries for HD-audio driver Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 775beea4506..abffd411232 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -136,6 +136,7 @@ ALC882/883/885/888/889 acer-aspire Acer Aspire 9810 acer-aspire-4930g Acer Aspire 4930G acer-aspire-6530g Acer Aspire 6530G + acer-aspire-7730g Acer Aspire 7730G acer-aspire-8930g Acer Aspire 8930G medion Medion Laptops medion-md2 Medion MD2 @@ -227,7 +228,7 @@ AD1984 ====== basic default configuration thinkpad Lenovo Thinkpad T61/X61 - dell Dell T3400 + dell_desktop Dell T3400 AD1986A ======= @@ -256,6 +257,7 @@ Conexant 5045 laptop-micsense Laptop with Mic sense (old model fujitsu) laptop-hpmicsense Laptop with HP and Mic senses benq Benq R55E + laptop-hp530 HP 530 laptop test for testing/debugging purpose, almost all controls can be adjusted. Appearing only when compiled with $CONFIG_SND_DEBUG=y @@ -276,9 +278,16 @@ Conexant 5051 hp-dv6736 HP dv6736 lenovo-x200 Lenovo X200 laptop +Conexant 5066 +============= + laptop Basic Laptop config (default) + dell-laptop Dell laptops + olpc-xo-1_5 OLPC XO 1.5 + STAC9200 ======== ref Reference board + oqo OQO Model 2 dell-d21 Dell (unknown) dell-d22 Dell (unknown) dell-d23 Dell (unknown) @@ -366,6 +375,7 @@ STAC92HD73* =========== ref Reference board no-jd BIOS setup but without jack-detection + intel Intel DG45* mobos dell-m6-amic Dell desktops/laptops with analog mics dell-m6-dmic Dell desktops/laptops with digital mics dell-m6 Dell desktops/laptops with both type of mics @@ -387,3 +397,4 @@ STAC9872 Cirrus Logic CS4206/4207 ======================== mbp55 MacBook Pro 5,5 + auto BIOS setup (default) -- cgit v1.2.3-70-g09d2 From 6591b493871cf9b17de2ba272edb8ab529a8058b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Thu, 6 Aug 2009 07:57:01 -0700 Subject: tracing: Add vim script to enable folding for function_graph traces function_graph traces look like nested function calls, complete with braces denoting the start and end of functions. function-graph-fold.vim teaches vim how to fold these functions, to make it more convenient to browse them. To use, :source function-graph-fold.vim while viewing a function_graph trace, or use "view -S function-graph-fold.vim some-trace" to load it from the command-line together with a trace. You can then use the usual vim fold commands, such as "za", to open and close nested functions. While closed, a fold will show the total time taken for a call, as would normally appear on the line with the closing brace. Folded functions will not include finish_task_switch(), so folding should remain relatively sane even through a context switch. Note that this will almost certainly only work well with a single-CPU trace (e.g. trace-cmd report --cpu 1). It also takes some time to run (a few seconds for a large trace on my laptop). Nevertheless, I found it very handy to get an overview of a trace and then drill down on problematic calls. Signed-off-by: Josh Triplett LKML-Reference: <20090806145701.GB7661@feather> Signed-off-by: Steven Rostedt --- Documentation/trace/function-graph-fold.vim | 42 +++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Documentation/trace/function-graph-fold.vim (limited to 'Documentation') diff --git a/Documentation/trace/function-graph-fold.vim b/Documentation/trace/function-graph-fold.vim new file mode 100644 index 00000000000..0544b504c8b --- /dev/null +++ b/Documentation/trace/function-graph-fold.vim @@ -0,0 +1,42 @@ +" Enable folding for ftrace function_graph traces. +" +" To use, :source this file while viewing a function_graph trace, or use vim's +" -S option to load from the command-line together with a trace. You can then +" use the usual vim fold commands, such as "za", to open and close nested +" functions. While closed, a fold will show the total time taken for a call, +" as would normally appear on the line with the closing brace. Folded +" functions will not include finish_task_switch(), so folding should remain +" relatively sane even through a context switch. +" +" Note that this will almost certainly only work well with a +" single-CPU trace (e.g. trace-cmd report --cpu 1). + +function! FunctionGraphFoldExpr(lnum) + let line = getline(a:lnum) + if line[-1:] == '{' + if line =~ 'finish_task_switch() {$' + return '>1' + endif + return 'a1' + elseif line[-1:] == '}' + return 's1' + else + return '=' + endif +endfunction + +function! FunctionGraphFoldText() + let s = split(getline(v:foldstart), '|', 1) + if getline(v:foldend+1) =~ 'finish_task_switch() {$' + let s[2] = ' task switch ' + else + let e = split(getline(v:foldend), '|', 1) + let s[2] = e[2] + endif + return join(s, '|') +endfunction + +setlocal foldexpr=FunctionGraphFoldExpr(v:lnum) +setlocal foldtext=FunctionGraphFoldText() +setlocal foldcolumn=12 +setlocal foldmethod=expr -- cgit v1.2.3-70-g09d2 From 189d84ed54bbb05aac5b24d9d784d86c4d37f807 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Thu, 27 Aug 2009 14:29:15 +0100 Subject: kmemleak: Dump object information on request By writing dump= to the kmemleak file, kmemleak will look up an object with that address and dump the information it has about it to syslog. This is useful in debugging memory leaks. Signed-off-by: Catalin Marinas --- Documentation/kmemleak.txt | 1 + mm/kmemleak.c | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kmemleak.txt b/Documentation/kmemleak.txt index 89068030b01..c223785339b 100644 --- a/Documentation/kmemleak.txt +++ b/Documentation/kmemleak.txt @@ -42,6 +42,7 @@ Memory scanning parameters can be modified at run-time by writing to the scan= - set the automatic memory scanning period in seconds (default 600, 0 to stop the automatic scanning) scan - trigger a memory scan + dump= - dump information about the object found at Kmemleak can also be disabled at boot-time by passing "kmemleak=off" on the kernel command line. diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 6debe0d80e6..c977f7a2f0e 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -331,6 +331,7 @@ static void dump_object_info(struct kmemleak_object *object) object->comm, object->pid, object->jiffies); pr_notice(" min_count = %d\n", object->min_count); pr_notice(" count = %d\n", object->count); + pr_notice(" flags = 0x%lx\n", object->flags); pr_notice(" backtrace:\n"); print_stack_trace(&trace, 4); } @@ -1307,6 +1308,27 @@ static int kmemleak_release(struct inode *inode, struct file *file) return seq_release(inode, file); } +static int dump_str_object_info(const char *str) +{ + unsigned long flags; + struct kmemleak_object *object; + unsigned long addr; + + addr= simple_strtoul(str, NULL, 0); + object = find_and_get_object(addr, 0); + if (!object) { + pr_info("Unknown object at 0x%08lx\n", addr); + return -EINVAL; + } + + spin_lock_irqsave(&object->lock, flags); + dump_object_info(object); + spin_unlock_irqrestore(&object->lock, flags); + + put_object(object); + return 0; +} + /* * File write operation to configure kmemleak at run-time. The following * commands can be written to the /sys/kernel/debug/kmemleak file: @@ -1318,6 +1340,7 @@ static int kmemleak_release(struct inode *inode, struct file *file) * scan=... - set the automatic memory scanning period in seconds (0 to * disable it) * scan - trigger a memory scan + * dump=... - dump information about the object found at the given address */ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf, size_t size, loff_t *ppos) @@ -1358,6 +1381,8 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf, } } else if (strncmp(buf, "scan", 4) == 0) kmemleak_scan(); + else if (strncmp(buf, "dump=", 5) == 0) + ret = dump_str_object_info(buf + 5); else ret = -EINVAL; -- cgit v1.2.3-70-g09d2 From 36ce99c1dcab2978fc1900f19b431adedd8f99f6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 27 Aug 2009 16:45:07 +0200 Subject: ALSA: Add debug module option Add debug module option to snd core. This controls the debug print level. When CONFIG_SND_DEBUG_VERBOSE is set, you can suppress the debug messages by giving or changing this parameter to a lower value. debug=0 means no debug messsages. As default, it's set to the verbose level 2. Since this option can be changed dynamically via sysfs file, you can suppress the verbose debug messages on the fly, which wasn't possible before. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 6 +++ include/sound/core.h | 38 ++++++-------- sound/core/misc.c | 67 ++++++++++++++----------- 3 files changed, 59 insertions(+), 52 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 4252697a95d..8e5b3488b37 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -60,6 +60,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. slots - Reserve the slot index for the given driver. This option takes multiple strings. See "Module Autoloading Support" section for details. + debug - Specifies the debug message level + (0 = disable debug prints, 1 = normal debug messages, + 2 = verbose debug messages) + This option appears only when CONFIG_SND_DEBUG=y. + This option can be dynamically changed via sysfs + /sys/modules/snd/parameters/debug file. Module snd-pcm-oss ------------------ diff --git a/include/sound/core.h b/include/sound/core.h index 309cb9659a0..a89728db558 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -340,18 +340,17 @@ unsigned int snd_dma_pointer(unsigned long dma, unsigned int size); struct resource; void release_and_free_resource(struct resource *res); -#ifdef CONFIG_SND_VERBOSE_PRINTK -void snd_verbose_printk(const char *file, int line, const char *format, ...) - __attribute__ ((format (printf, 3, 4))); -#endif -#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK) -void snd_verbose_printd(const char *file, int line, const char *format, ...) - __attribute__ ((format (printf, 3, 4))); -#endif - /* --- */ -#ifdef CONFIG_SND_VERBOSE_PRINTK +#if defined(CONFIG_SND_DEBUG) || defined(CONFIG_SND_VERBOSE_PRINTK) +void __snd_printk(unsigned int level, const char *file, int line, + const char *format, ...) + __attribute__ ((format (printf, 4, 5))); +#else +#define __snd_printk(level, file, line, format, args...) \ + prinkt(format, ##args) +#endif + /** * snd_printk - printk wrapper * @fmt: format string @@ -360,15 +359,9 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) * when configured with CONFIG_SND_VERBOSE_PRINTK. */ #define snd_printk(fmt, args...) \ - snd_verbose_printk(__FILE__, __LINE__, fmt ,##args) -#else -#define snd_printk(fmt, args...) \ - printk(fmt ,##args) -#endif + __snd_printk(0, __FILE__, __LINE__, fmt, ##args) #ifdef CONFIG_SND_DEBUG - -#ifdef CONFIG_SND_VERBOSE_PRINTK /** * snd_printd - debug printk * @fmt: format string @@ -377,11 +370,7 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...) * Ignored when CONFIG_SND_DEBUG is not set. */ #define snd_printd(fmt, args...) \ - snd_verbose_printd(__FILE__, __LINE__, fmt ,##args) -#else -#define snd_printd(fmt, args...) \ - printk(fmt ,##args) -#endif + __snd_printk(1, __FILE__, __LINE__, fmt, ##args) /** * snd_BUG - give a BUG warning message and stack trace @@ -428,9 +417,10 @@ static inline int __snd_bug_on(int cond) * Works like snd_printk() for debugging purposes. * Ignored when CONFIG_SND_DEBUG_VERBOSE is not set. */ -#define snd_printdd(format, args...) snd_printk(format, ##args) +#define snd_printdd(format, args...) \ + __snd_printk(2, __FILE__, __LINE__, format, ##args) #else -#define snd_printdd(format, args...) /* nothing */ +#define snd_printdd(format, args...) do { } while (0) #endif diff --git a/sound/core/misc.c b/sound/core/misc.c index 1d29e678369..23a032c6d48 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -24,6 +24,20 @@ #include #include +#ifdef CONFIG_SND_DEBUG + +#ifdef CONFIG_SND_DEBUG_VERBOSE +#define DEFAULT_DEBUG_LEVEL 2 +#else +#define DEFAULT_DEBUG_LEVEL 1 +#endif + +static int debug = DEFAULT_DEBUG_LEVEL; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Debug level (0 = disable)"); + +#endif /* CONFIG_SND_DEBUG */ + void release_and_free_resource(struct resource *res) { if (res) { @@ -35,6 +49,7 @@ void release_and_free_resource(struct resource *res) EXPORT_SYMBOL(release_and_free_resource); #ifdef CONFIG_SND_VERBOSE_PRINTK +/* strip the leading path if the given path is absolute */ static const char *sanity_file_name(const char *path) { if (*path == '/') @@ -43,48 +58,44 @@ static const char *sanity_file_name(const char *path) return path; } -void snd_verbose_printk(const char *path, int line, const char *format, ...) +/* print file and line with a certain printk prefix */ +static int print_snd_pfx(unsigned int level, const char *path, int line, + const char *format) { const char *file = sanity_file_name(path); - va_list args; - - if (format[0] == '<' && format[1] >= '0' && format[1] <= '7' && format[2] == '>') { - char tmp[] = "<0>"; + char tmp[] = "<0>"; + const char *pfx = level ? KERN_DEBUG : KERN_DEFAULT; + int ret = 0; + + if (format[0] == '<' && format[2] == '>') { tmp[1] = format[1]; - printk("%sALSA %s:%d: ", tmp, file, line); - format += 3; - } else { - printk("ALSA %s:%d: ", file, line); + pfx = tmp; + ret = 1; } - va_start(args, format); - vprintk(format, args); - va_end(args); + printk("%sALSA %s:%d: ", pfx, file, line); + return ret; } - -EXPORT_SYMBOL(snd_verbose_printk); +#else +#define print_snd_pfx(level, path, line, format) 0 #endif -#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK) -void snd_verbose_printd(const char *path, int line, const char *format, ...) +#if defined(CONFIG_SND_DEBUG) || defined(CONFIG_SND_VERBOSE_PRINTK) +void __snd_printk(unsigned int level, const char *path, int line, + const char *format, ...) { - const char *file = sanity_file_name(path); va_list args; - if (format[0] == '<' && format[1] >= '0' && format[1] <= '7' && format[2] == '>') { - char tmp[] = "<0>"; - tmp[1] = format[1]; - printk("%sALSA %s:%d: ", tmp, file, line); - format += 3; - } else { - printk(KERN_DEBUG "ALSA %s:%d: ", file, line); - } +#ifdef CONFIG_SND_DEBUG + if (debug < level) + return; +#endif va_start(args, format); + if (print_snd_pfx(level, path, line, format)) + format += 3; /* skip the printk level-prefix */ vprintk(format, args); va_end(args); - } - -EXPORT_SYMBOL(snd_verbose_printd); +EXPORT_SYMBOL_GPL(__snd_printk); #endif #ifdef CONFIG_PCI -- cgit v1.2.3-70-g09d2 From ff55df53dfdd338906c8ba9d1f4a759b86b869d5 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Mon, 31 Aug 2009 14:16:57 -0700 Subject: x86, msr: Export the register-setting MSR functions via /dev/*/msr Make it possible to access the all-register-setting/getting MSR functions via the MSR driver. This is implemented as an ioctl() on the standard MSR device node. Signed-off-by: H. Peter Anvin Cc: Borislav Petkov --- Documentation/ioctl/ioctl-number.txt | 1 + arch/x86/include/asm/msr.h | 10 +++++-- arch/x86/kernel/msr.c | 51 ++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index dbea4f95fc8..1c058b552e9 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -121,6 +121,7 @@ Code Seq# Include File Comments 'c' 00-7F linux/comstats.h conflict! 'c' 00-7F linux/coda.h conflict! 'c' 80-9F arch/s390/include/asm/chsc.h +'c' A0-AF arch/x86/include/asm/msr.h 'd' 00-FF linux/char/drm/drm/h conflict! 'd' F0-FF linux/digi1.h 'e' all linux/digi1.h conflict! diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index 8e56712aa17..7e2b6ba962f 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -3,10 +3,16 @@ #include -#ifdef __KERNEL__ #ifndef __ASSEMBLY__ #include +#include + +#define X86_IOC_RDMSR_REGS _IOWR('c', 0xA0, __u32[8]) +#define X86_IOC_WRMSR_REGS _IOWR('c', 0xA1, __u32[8]) + +#ifdef __KERNEL__ + #include #include #include @@ -286,6 +292,6 @@ static inline int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 regs[8]) return wrmsr_safe_regs(regs); } #endif /* CONFIG_SMP */ -#endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ +#endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_MSR_H */ diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c index 2cfbb4b2c42..7dd95009417 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -1,6 +1,7 @@ /* ----------------------------------------------------------------------- * * * Copyright 2000-2008 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -121,6 +122,54 @@ static ssize_t msr_write(struct file *file, const char __user *buf, return bytes ? bytes : err; } +static long msr_ioctl(struct file *file, unsigned int ioc, unsigned long arg) +{ + u32 __user *uregs = (u32 __user *)arg; + u32 regs[8]; + int cpu = iminor(file->f_path.dentry->d_inode); + int err; + + switch (ioc) { + case X86_IOC_RDMSR_REGS: + if (!(file->f_mode & FMODE_READ)) { + err = -EBADF; + break; + } + if (copy_from_user(®s, uregs, sizeof regs)) { + err = -EFAULT; + break; + } + err = rdmsr_safe_regs_on_cpu(cpu, regs); + if (err) + break; + if (copy_to_user(uregs, ®s, sizeof regs)) + err = -EFAULT; + break; + + case X86_IOC_WRMSR_REGS: + if (!(file->f_mode & FMODE_WRITE)) { + err = -EBADF; + break; + } + if (copy_from_user(®s, uregs, sizeof regs)) { + err = -EFAULT; + break; + } + err = wrmsr_safe_regs_on_cpu(cpu, regs); + if (err) + break; + if (copy_to_user(uregs, ®s, sizeof regs)) + err = -EFAULT; + break; + + default: + err = -ENOTTY; + break; + } + + return err; +} + static int msr_open(struct inode *inode, struct file *file) { unsigned int cpu = iminor(file->f_path.dentry->d_inode); @@ -151,6 +200,8 @@ static const struct file_operations msr_fops = { .read = msr_read, .write = msr_write, .open = msr_open, + .unlocked_ioctl = msr_ioctl, + .compat_ioctl = msr_ioctl, }; static int __cpuinit msr_device_create(int cpu) -- cgit v1.2.3-70-g09d2 From 051d9fbdd1d1ec85ea18ba20581234cf23f1c217 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 3 Jul 2009 11:46:12 +0900 Subject: libata: remove spindown skipping and warning This was a hack to give userland shutdown tools time to drop manual spindown. All popular distros updated quite some time ago and the due is well passed. Drop it. Signed-off-by: Tejun Heo Cc: Jaswinder Singh Rajput Signed-off-by: Jeff Garzik --- Documentation/feature-removal-schedule.txt | 18 ----------- drivers/ata/libata-scsi.c | 51 ------------------------------ include/linux/libata.h | 1 - 3 files changed, 70 deletions(-) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 09e031c5588..b3b62903f08 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -206,24 +206,6 @@ Who: Len Brown --------------------------- -What: libata spindown skipping and warning -When: Dec 2008 -Why: Some halt(8) implementations synchronize caches for and spin - down libata disks because libata didn't use to spin down disk on - system halt (only synchronized caches). - Spin down on system halt is now implemented. sysfs node - /sys/class/scsi_disk/h:c:i:l/manage_start_stop is present if - spin down support is available. - Because issuing spin down command to an already spun down disk - makes some disks spin up just to spin down again, libata tracks - device spindown status to skip the extra spindown command and - warn about it. - This is to give userspace tools the time to get updated and will - be removed after userspace is reasonably updated. -Who: Tejun Heo - ---------------------------- - What: i386/x86_64 bzImage symlinks When: April 2010 diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d0dfeef55db..de3a0050760 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1257,23 +1257,6 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth) return queue_depth; } -/* XXX: for spindown warning */ -static void ata_delayed_done_timerfn(unsigned long arg) -{ - struct scsi_cmnd *scmd = (void *)arg; - - scmd->scsi_done(scmd); -} - -/* XXX: for spindown warning */ -static void ata_delayed_done(struct scsi_cmnd *scmd) -{ - static struct timer_list timer; - - setup_timer(&timer, ata_delayed_done_timerfn, (unsigned long)scmd); - mod_timer(&timer, jiffies + 5 * HZ); -} - /** * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command * @qc: Storage for translated ATA taskfile @@ -1338,32 +1321,6 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) system_entering_hibernation()) goto skip; - /* XXX: This is for backward compatibility, will be - * removed. Read Documentation/feature-removal-schedule.txt - * for more info. - */ - if ((qc->dev->flags & ATA_DFLAG_SPUNDOWN) && - (system_state == SYSTEM_HALT || - system_state == SYSTEM_POWER_OFF)) { - static unsigned long warned; - - if (!test_and_set_bit(0, &warned)) { - ata_dev_printk(qc->dev, KERN_WARNING, - "DISK MIGHT NOT BE SPUN DOWN PROPERLY. " - "UPDATE SHUTDOWN UTILITY\n"); - ata_dev_printk(qc->dev, KERN_WARNING, - "For more info, visit " - "http://linux-ata.org/shutdown.html\n"); - - /* ->scsi_done is not used, use it for - * delayed completion. - */ - scmd->scsi_done = qc->scsidone; - qc->scsidone = ata_delayed_done; - } - goto skip; - } - /* Issue ATA STANDBY IMMEDIATE command */ tf->command = ATA_CMD_STANDBYNOW1; } @@ -1764,14 +1721,6 @@ static void ata_scsi_qc_complete(struct ata_queued_cmd *qc) } } - /* XXX: track spindown state for spindown skipping and warning */ - if (unlikely(qc->tf.command == ATA_CMD_STANDBY || - qc->tf.command == ATA_CMD_STANDBYNOW1)) - qc->dev->flags |= ATA_DFLAG_SPUNDOWN; - else if (likely(system_state != SYSTEM_HALT && - system_state != SYSTEM_POWER_OFF)) - qc->dev->flags &= ~ATA_DFLAG_SPUNDOWN; - if (need_sense && !ap->ops->error_handler) ata_dump_status(ap->print_id, &qc->result_tf); diff --git a/include/linux/libata.h b/include/linux/libata.h index d3f7cab4873..76319bf03e3 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -143,7 +143,6 @@ enum { ATA_DFLAG_PIO = (1 << 12), /* device limited to PIO mode */ ATA_DFLAG_NCQ_OFF = (1 << 13), /* device limited to non-NCQ mode */ - ATA_DFLAG_SPUNDOWN = (1 << 14), /* XXX: for spindown_compat */ ATA_DFLAG_SLEEPING = (1 << 15), /* device is sleeping */ ATA_DFLAG_DUBIOUS_XFER = (1 << 16), /* data transfer not verified */ ATA_DFLAG_NO_UNLOAD = (1 << 17), /* device doesn't support unload */ -- cgit v1.2.3-70-g09d2 From 5d7892298a819743b3892df08bb496992fe85951 Mon Sep 17 00:00:00 2001 From: Damian Lukowski Date: Tue, 1 Sep 2009 10:24:04 +0000 Subject: RTO connection timeout: sysctl documentation update This patch updates the sysctl documentation concerning the interpretation of tcp_retries{1,2} and tcp_orphan_retries. Signed-off-by: Damian Lukowski Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 37 ++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 8be76235fe6..4e9c6d7b4ef 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -311,9 +311,12 @@ tcp_no_metrics_save - BOOLEAN connections. tcp_orphan_retries - INTEGER - How may times to retry before killing TCP connection, closed - by our side. Default value 7 corresponds to ~50sec-16min - depending on RTO. If you machine is loaded WEB server, + This value influences the timeout of a locally closed TCP connection, + when RTO retransmissions remain unacknowledged. + See tcp_retries2 for more details. + + The default value is 7. + If your machine is a loaded WEB server, you should think about lowering this value, such sockets may consume significant resources. Cf. tcp_max_orphans. @@ -327,16 +330,28 @@ tcp_retrans_collapse - BOOLEAN certain TCP stacks. tcp_retries1 - INTEGER - How many times to retry before deciding that something is wrong - and it is necessary to report this suspicion to network layer. - Minimal RFC value is 3, it is default, which corresponds - to ~3sec-8min depending on RTO. + This value influences the time, after which TCP decides, that + something is wrong due to unacknowledged RTO retransmissions, + and reports this suspicion to the network layer. + See tcp_retries2 for more details. + + RFC 1122 recommends at least 3 retransmissions, which is the + default. tcp_retries2 - INTEGER - How may times to retry before killing alive TCP connection. - RFC1122 says that the limit should be longer than 100 sec. - It is too small number. Default value 15 corresponds to ~13-30min - depending on RTO. + This value influences the timeout of an alive TCP connection, + when RTO retransmissions remain unacknowledged. + Given a value of N, a hypothetical TCP connection following + exponential backoff with an initial RTO of TCP_RTO_MIN would + retransmit N times before killing the connection at the (N+1)th RTO. + + The default value of 15 yields a hypothetical timeout of 924.6 + seconds and is a lower bound for the effective timeout. + TCP will effectively time out at the first RTO which exceeds the + hypothetical timeout. + + RFC 1122 recommends at least 100 seconds for the timeout, + which corresponds to a value of at least 8. tcp_rfc1337 - BOOLEAN If set, the TCP stack behaves conforming to RFC1337. If unset, -- cgit v1.2.3-70-g09d2 From 842ae63800bc2be62085d7ce5b3a2298c014d37a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 2 Sep 2009 07:43:08 +0200 Subject: ALSA: hda - Add support of Alienware M17x laptop Added the quirk for Alienware M17x with IDT 92HD73* codec chip. It has two HP and one line-out jack, one mic jack, a built-in speaker and a built-in mic. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 1 + sound/pci/hda/patch_sigmatel.c | 27 +++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index abffd411232..32d8cc05d15 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -380,6 +380,7 @@ STAC92HD73* dell-m6-dmic Dell desktops/laptops with digital mics dell-m6 Dell desktops/laptops with both type of mics dell-eq Dell desktops/laptops + alienware Alienware M17x auto BIOS setup (default) STAC92HD83* diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 83a338b9c08..e31e53dc696 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -83,6 +83,7 @@ enum { STAC_DELL_M6_DMIC, STAC_DELL_M6_BOTH, STAC_DELL_EQ, + STAC_ALIENWARE_M17X, STAC_92HD73XX_MODELS }; @@ -1513,12 +1514,20 @@ static unsigned int dell_m6_pin_configs[13] = { 0x4f0000f0, }; +static unsigned int alienware_m17x_pin_configs[13] = { + 0x0321101f, 0x0321101f, 0x03a11020, 0x03014020, + 0x90170110, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0, + 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0, + 0x904601b0, +}; + static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs, [STAC_DELL_M6_AMIC] = dell_m6_pin_configs, [STAC_DELL_M6_DMIC] = dell_m6_pin_configs, [STAC_DELL_M6_BOTH] = dell_m6_pin_configs, [STAC_DELL_EQ] = dell_m6_pin_configs, + [STAC_ALIENWARE_M17X] = alienware_m17x_pin_configs, }; static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = { @@ -1530,6 +1539,7 @@ static const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = { [STAC_DELL_M6_DMIC] = "dell-m6-dmic", [STAC_DELL_M6_BOTH] = "dell-m6", [STAC_DELL_EQ] = "dell-eq", + [STAC_ALIENWARE_M17X] = "alienware", }; static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { @@ -1567,6 +1577,12 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { {} /* terminator */ }; +static struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1, + "Alienware M17x", STAC_ALIENWARE_M17X), + {} /* terminator */ +}; + static unsigned int ref92hd83xxx_pin_configs[10] = { 0x02214030, 0x02211010, 0x02a19020, 0x02170130, 0x01014050, 0x01819040, 0x01014020, 0x90a3014e, @@ -4909,6 +4925,12 @@ static int patch_stac92hd73xx(struct hda_codec *codec) STAC_92HD73XX_MODELS, stac92hd73xx_models, stac92hd73xx_cfg_tbl); + /* check codec subsystem id if not found */ + if (spec->board_config < 0) + spec->board_config = + snd_hda_check_board_codec_sid_config(codec, + STAC_92HD73XX_MODELS, stac92hd73xx_models, + stac92hd73xx_codec_id_cfg_tbl); again: if (spec->board_config < 0) snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", @@ -4983,6 +5005,11 @@ again: break; } break; + case STAC_ALIENWARE_M17X: + spec->num_dmics = STAC92HD73XX_NUM_DMICS; + spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); + spec->eapd_switch = 0; + break; default: spec->num_dmics = STAC92HD73XX_NUM_DMICS; spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); -- cgit v1.2.3-70-g09d2 From 5d135440faf7db8d566de0c6fab36b16cf9cfc3b Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 2 Sep 2009 09:14:00 +0100 Subject: KEYS: Add garbage collection for dead, revoked and expired keys. [try #6] Add garbage collection for dead, revoked and expired keys. This involved erasing all links to such keys from keyrings that point to them. At that point, the key will be deleted in the normal manner. Keyrings from which garbage collection occurs are shrunk and their quota consumption reduced as appropriate. Dead keys (for which the key type has been removed) will be garbage collected immediately. Revoked and expired keys will hang around for a number of seconds, as set in /proc/sys/kernel/keys/gc_delay before being automatically removed. The default is 5 minutes. Signed-off-by: David Howells Signed-off-by: James Morris --- Documentation/keys.txt | 19 ++++- include/linux/key.h | 5 +- security/keys/Makefile | 1 + security/keys/gc.c | 193 +++++++++++++++++++++++++++++++++++++++++++++++ security/keys/internal.h | 4 + security/keys/key.c | 14 ++++ security/keys/keyctl.c | 1 + security/keys/keyring.c | 85 +++++++++++++++++++++ security/keys/sysctl.c | 28 ++++++- 9 files changed, 344 insertions(+), 6 deletions(-) create mode 100644 security/keys/gc.c (limited to 'Documentation') diff --git a/Documentation/keys.txt b/Documentation/keys.txt index b56aacc1fff..203487e9b1d 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt @@ -26,7 +26,7 @@ This document has the following sections: - Notes on accessing payload contents - Defining a key type - Request-key callback service - - Key access filesystem + - Garbage collection ============ @@ -113,6 +113,9 @@ Each key has a number of attributes: (*) Dead. The key's type was unregistered, and so the key is now useless. +Keys in the last three states are subject to garbage collection. See the +section on "Garbage collection". + ==================== KEY SERVICE OVERVIEW @@ -1231,3 +1234,17 @@ by executing: In this case, the program isn't required to actually attach the key to a ring; the rings are provided for reference. + + +================== +GARBAGE COLLECTION +================== + +Dead keys (for which the type has been removed) will be automatically unlinked +from those keyrings that point to them and deleted as soon as possible by a +background garbage collector. + +Similarly, revoked and expired keys will be garbage collected, but only after a +certain amount of time has passed. This time is set as a number of seconds in: + + /proc/sys/kernel/keys/gc_delay diff --git a/include/linux/key.h b/include/linux/key.h index e544f466d69..33e0165de10 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -129,7 +129,10 @@ struct key { struct rw_semaphore sem; /* change vs change sem */ struct key_user *user; /* owner of this key */ void *security; /* security data for this key */ - time_t expiry; /* time at which key expires (or 0) */ + union { + time_t expiry; /* time at which key expires (or 0) */ + time_t revoked_at; /* time at which key was revoked */ + }; uid_t uid; gid_t gid; key_perm_t perm; /* access permissions */ diff --git a/security/keys/Makefile b/security/keys/Makefile index 747a464943a..74d5447d7df 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile @@ -3,6 +3,7 @@ # obj-y := \ + gc.o \ key.o \ keyring.o \ keyctl.o \ diff --git a/security/keys/gc.c b/security/keys/gc.c new file mode 100644 index 00000000000..44adc325e15 --- /dev/null +++ b/security/keys/gc.c @@ -0,0 +1,193 @@ +/* Key garbage collector + * + * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ + +#include +#include +#include "internal.h" + +/* + * Delay between key revocation/expiry in seconds + */ +unsigned key_gc_delay = 5 * 60; + +/* + * Reaper + */ +static void key_gc_timer_func(unsigned long); +static void key_garbage_collector(struct work_struct *); +static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0); +static DECLARE_WORK(key_gc_work, key_garbage_collector); +static key_serial_t key_gc_cursor; /* the last key the gc considered */ +static unsigned long key_gc_executing; +static time_t key_gc_next_run = LONG_MAX; + +/* + * Schedule a garbage collection run + * - precision isn't particularly important + */ +void key_schedule_gc(time_t gc_at) +{ + unsigned long expires; + time_t now = current_kernel_time().tv_sec; + + kenter("%ld", gc_at - now); + + gc_at += key_gc_delay; + + if (now >= gc_at) { + schedule_work(&key_gc_work); + } else if (gc_at < key_gc_next_run) { + expires = jiffies + (gc_at - now) * HZ; + mod_timer(&key_gc_timer, expires); + } +} + +/* + * The garbage collector timer kicked off + */ +static void key_gc_timer_func(unsigned long data) +{ + kenter(""); + key_gc_next_run = LONG_MAX; + schedule_work(&key_gc_work); +} + +/* + * Garbage collect pointers from a keyring + * - return true if we altered the keyring + */ +static bool key_gc_keyring(struct key *keyring, time_t limit) +{ + struct keyring_list *klist; + struct key *key; + int loop; + + kenter("%x", key_serial(keyring)); + + if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) + goto dont_gc; + + /* scan the keyring looking for dead keys */ + klist = rcu_dereference(keyring->payload.subscriptions); + if (!klist) + goto dont_gc; + + for (loop = klist->nkeys - 1; loop >= 0; loop--) { + key = klist->keys[loop]; + if (test_bit(KEY_FLAG_DEAD, &key->flags) || + (key->expiry > 0 && key->expiry <= limit)) + goto do_gc; + } + +dont_gc: + kleave(" = false"); + return false; + +do_gc: + key_gc_cursor = keyring->serial; + key_get(keyring); + spin_unlock(&key_serial_lock); + keyring_gc(keyring, limit); + key_put(keyring); + kleave(" = true"); + return true; +} + +/* + * Garbage collector for keys + * - this involves scanning the keyrings for dead, expired and revoked keys + * that have overstayed their welcome + */ +static void key_garbage_collector(struct work_struct *work) +{ + struct rb_node *rb; + key_serial_t cursor; + struct key *key, *xkey; + time_t new_timer = LONG_MAX, limit; + + kenter(""); + + if (test_and_set_bit(0, &key_gc_executing)) { + key_schedule_gc(current_kernel_time().tv_sec); + return; + } + + limit = current_kernel_time().tv_sec; + if (limit > key_gc_delay) + limit -= key_gc_delay; + else + limit = key_gc_delay; + + spin_lock(&key_serial_lock); + + if (RB_EMPTY_ROOT(&key_serial_tree)) + goto reached_the_end; + + cursor = key_gc_cursor; + if (cursor < 0) + cursor = 0; + + /* find the first key above the cursor */ + key = NULL; + rb = key_serial_tree.rb_node; + while (rb) { + xkey = rb_entry(rb, struct key, serial_node); + if (cursor < xkey->serial) { + key = xkey; + rb = rb->rb_left; + } else if (cursor > xkey->serial) { + rb = rb->rb_right; + } else { + rb = rb_next(rb); + if (!rb) + goto reached_the_end; + key = rb_entry(rb, struct key, serial_node); + break; + } + } + + if (!key) + goto reached_the_end; + + /* trawl through the keys looking for keyrings */ + for (;;) { + if (key->expiry > 0 && key->expiry < new_timer) + new_timer = key->expiry; + + if (key->type == &key_type_keyring && + key_gc_keyring(key, limit)) { + /* the gc ate our lock */ + schedule_work(&key_gc_work); + goto no_unlock; + } + + rb = rb_next(&key->serial_node); + if (!rb) { + key_gc_cursor = 0; + break; + } + key = rb_entry(rb, struct key, serial_node); + } + +out: + spin_unlock(&key_serial_lock); +no_unlock: + clear_bit(0, &key_gc_executing); + if (new_timer < LONG_MAX) + key_schedule_gc(new_timer); + + kleave(""); + return; + +reached_the_end: + key_gc_cursor = 0; + goto out; +} diff --git a/security/keys/internal.h b/security/keys/internal.h index a7252e7b2e0..fb830514c33 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -132,6 +132,10 @@ extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags, extern long join_session_keyring(const char *name); +extern unsigned key_gc_delay; +extern void keyring_gc(struct key *keyring, time_t limit); +extern void key_schedule_gc(time_t expiry_at); + /* * check to see whether permission is granted to use a key in the desired way */ diff --git a/security/keys/key.c b/security/keys/key.c index bd9d2670e9c..08531ad0f25 100644 --- a/security/keys/key.c +++ b/security/keys/key.c @@ -500,6 +500,7 @@ int key_negate_and_link(struct key *key, set_bit(KEY_FLAG_INSTANTIATED, &key->flags); now = current_kernel_time(); key->expiry = now.tv_sec + timeout; + key_schedule_gc(key->expiry); if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) awaken = 1; @@ -888,6 +889,9 @@ EXPORT_SYMBOL(key_update); */ void key_revoke(struct key *key) { + struct timespec now; + time_t time; + key_check(key); /* make sure no one's trying to change or use the key when we mark it @@ -900,6 +904,14 @@ void key_revoke(struct key *key) key->type->revoke) key->type->revoke(key); + /* set the death time to no more than the expiry time */ + now = current_kernel_time(); + time = now.tv_sec; + if (key->revoked_at == 0 || key->revoked_at > time) { + key->revoked_at = time; + key_schedule_gc(key->revoked_at); + } + up_write(&key->sem); } /* end key_revoke() */ @@ -984,6 +996,8 @@ void unregister_key_type(struct key_type *ktype) spin_unlock(&key_serial_lock); up_write(&key_types_sem); + key_schedule_gc(0); + } /* end unregister_key_type() */ EXPORT_SYMBOL(unregister_key_type); diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 1160b644dac..736d7800f97 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -1115,6 +1115,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) } key->expiry = expiry; + key_schedule_gc(key->expiry); up_write(&key->sem); key_put(key); diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 3dba81c2eba..ac977f661a7 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c @@ -1000,3 +1000,88 @@ static void keyring_revoke(struct key *keyring) } } /* end keyring_revoke() */ + +/* + * Determine whether a key is dead + */ +static bool key_is_dead(struct key *key, time_t limit) +{ + return test_bit(KEY_FLAG_DEAD, &key->flags) || + (key->expiry > 0 && key->expiry <= limit); +} + +/* + * Collect garbage from the contents of a keyring + */ +void keyring_gc(struct key *keyring, time_t limit) +{ + struct keyring_list *klist, *new; + struct key *key; + int loop, keep, max; + + kenter("%x", key_serial(keyring)); + + down_write(&keyring->sem); + + klist = keyring->payload.subscriptions; + if (!klist) + goto just_return; + + /* work out how many subscriptions we're keeping */ + keep = 0; + for (loop = klist->nkeys - 1; loop >= 0; loop--) + if (!key_is_dead(klist->keys[loop], limit)); + keep++; + + if (keep == klist->nkeys) + goto just_return; + + /* allocate a new keyring payload */ + max = roundup(keep, 4); + new = kmalloc(sizeof(struct keyring_list) + max * sizeof(struct key *), + GFP_KERNEL); + if (!new) + goto just_return; + new->maxkeys = max; + new->nkeys = 0; + new->delkey = 0; + + /* install the live keys + * - must take care as expired keys may be updated back to life + */ + keep = 0; + for (loop = klist->nkeys - 1; loop >= 0; loop--) { + key = klist->keys[loop]; + if (!key_is_dead(key, limit)) { + if (keep >= max) + goto discard_new; + new->keys[keep++] = key_get(key); + } + } + new->nkeys = keep; + + /* adjust the quota */ + key_payload_reserve(keyring, + sizeof(struct keyring_list) + + KEYQUOTA_LINK_BYTES * keep); + + if (keep == 0) { + rcu_assign_pointer(keyring->payload.subscriptions, NULL); + kfree(new); + } else { + rcu_assign_pointer(keyring->payload.subscriptions, new); + } + + up_write(&keyring->sem); + + call_rcu(&klist->rcu, keyring_clear_rcu_disposal); + kleave(" [yes]"); + return; + +discard_new: + new->nkeys = keep; + keyring_clear_rcu_disposal(&new->rcu); +just_return: + up_write(&keyring->sem); + kleave(" [no]"); +} diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c index b611d493c2d..5e05dc09e2d 100644 --- a/security/keys/sysctl.c +++ b/security/keys/sysctl.c @@ -13,6 +13,8 @@ #include #include "internal.h" +static const int zero, one = 1, max = INT_MAX; + ctl_table key_sysctls[] = { { .ctl_name = CTL_UNNUMBERED, @@ -20,7 +22,9 @@ ctl_table key_sysctls[] = { .data = &key_quota_maxkeys, .maxlen = sizeof(unsigned), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = &proc_dointvec_minmax, + .extra1 = (void *) &one, + .extra2 = (void *) &max, }, { .ctl_name = CTL_UNNUMBERED, @@ -28,7 +32,9 @@ ctl_table key_sysctls[] = { .data = &key_quota_maxbytes, .maxlen = sizeof(unsigned), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = &proc_dointvec_minmax, + .extra1 = (void *) &one, + .extra2 = (void *) &max, }, { .ctl_name = CTL_UNNUMBERED, @@ -36,7 +42,9 @@ ctl_table key_sysctls[] = { .data = &key_quota_root_maxkeys, .maxlen = sizeof(unsigned), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = &proc_dointvec_minmax, + .extra1 = (void *) &one, + .extra2 = (void *) &max, }, { .ctl_name = CTL_UNNUMBERED, @@ -44,7 +52,19 @@ ctl_table key_sysctls[] = { .data = &key_quota_root_maxbytes, .maxlen = sizeof(unsigned), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = &proc_dointvec_minmax, + .extra1 = (void *) &one, + .extra2 = (void *) &max, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "gc_delay", + .data = &key_gc_delay, + .maxlen = sizeof(unsigned), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .extra1 = (void *) &zero, + .extra2 = (void *) &max, }, { .ctl_name = 0 } }; -- cgit v1.2.3-70-g09d2 From ee18d64c1f632043a02e6f5ba5e045bb26a5465f Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 2 Sep 2009 09:14:21 +0100 Subject: KEYS: Add a keyctl to install a process's session keyring on its parent [try #6] Add a keyctl to install a process's session keyring onto its parent. This replaces the parent's session keyring. Because the COW credential code does not permit one process to change another process's credentials directly, the change is deferred until userspace next starts executing again. Normally this will be after a wait*() syscall. To support this, three new security hooks have been provided: cred_alloc_blank() to allocate unset security creds, cred_transfer() to fill in the blank security creds and key_session_to_parent() - which asks the LSM if the process may replace its parent's session keyring. The replacement may only happen if the process has the same ownership details as its parent, and the process has LINK permission on the session keyring, and the session keyring is owned by the process, and the LSM permits it. Note that this requires alteration to each architecture's notify_resume path. This has been done for all arches barring blackfin, m68k* and xtensa, all of which need assembly alteration to support TIF_NOTIFY_RESUME. This allows the replacement to be performed at the point the parent process resumes userspace execution. This allows the userspace AFS pioctl emulation to fully emulate newpag() and the VIOCSETTOK and VIOCSETTOK2 pioctls, all of which require the ability to alter the parent process's PAG membership. However, since kAFS doesn't use PAGs per se, but rather dumps the keys into the session keyring, the session keyring of the parent must be replaced if, for example, VIOCSETTOK is passed the newpag flag. This can be tested with the following program: #include #include #include #define KEYCTL_SESSION_TO_PARENT 18 #define OSERROR(X, S) do { if ((long)(X) == -1) { perror(S); exit(1); } } while(0) int main(int argc, char **argv) { key_serial_t keyring, key; long ret; keyring = keyctl_join_session_keyring(argv[1]); OSERROR(keyring, "keyctl_join_session_keyring"); key = add_key("user", "a", "b", 1, keyring); OSERROR(key, "add_key"); ret = keyctl(KEYCTL_SESSION_TO_PARENT); OSERROR(ret, "KEYCTL_SESSION_TO_PARENT"); return 0; } Compiled and linked with -lkeyutils, you should see something like: [dhowells@andromeda ~]$ keyctl show Session Keyring -3 --alswrv 4043 4043 keyring: _ses 355907932 --alswrv 4043 -1 \_ keyring: _uid.4043 [dhowells@andromeda ~]$ /tmp/newpag [dhowells@andromeda ~]$ keyctl show Session Keyring -3 --alswrv 4043 4043 keyring: _ses 1055658746 --alswrv 4043 4043 \_ user: a [dhowells@andromeda ~]$ /tmp/newpag hello [dhowells@andromeda ~]$ keyctl show Session Keyring -3 --alswrv 4043 4043 keyring: hello 340417692 --alswrv 4043 4043 \_ user: a Where the test program creates a new session keyring, sticks a user key named 'a' into it and then installs it on its parent. Signed-off-by: David Howells Signed-off-by: James Morris --- Documentation/keys.txt | 20 +++++++++ arch/alpha/kernel/signal.c | 2 + arch/arm/kernel/signal.c | 2 + arch/avr32/kernel/signal.c | 2 + arch/cris/kernel/ptrace.c | 2 + arch/frv/kernel/signal.c | 2 + arch/h8300/kernel/signal.c | 2 + arch/ia64/kernel/process.c | 2 + arch/m32r/kernel/signal.c | 2 + arch/mips/kernel/signal.c | 2 + arch/mn10300/kernel/signal.c | 2 + arch/parisc/kernel/signal.c | 2 + arch/s390/kernel/signal.c | 2 + arch/sh/kernel/signal_32.c | 2 + arch/sh/kernel/signal_64.c | 2 + arch/sparc/kernel/signal_32.c | 2 + arch/sparc/kernel/signal_64.c | 3 ++ arch/x86/kernel/signal.c | 2 + include/linux/cred.h | 1 + include/linux/key.h | 3 ++ include/linux/keyctl.h | 1 + include/linux/sched.h | 1 + include/linux/security.h | 38 ++++++++++++++++ kernel/cred.c | 43 ++++++++++++++++++ security/capability.c | 19 ++++++++ security/keys/compat.c | 3 ++ security/keys/gc.c | 1 + security/keys/internal.h | 1 + security/keys/keyctl.c | 102 ++++++++++++++++++++++++++++++++++++++++++ security/keys/process_keys.c | 49 ++++++++++++++++++++ security/security.c | 17 +++++++ security/selinux/hooks.c | 28 ++++++++++++ security/smack/smack_lsm.c | 30 +++++++++++++ security/tomoyo/tomoyo.c | 17 +++++++ 34 files changed, 409 insertions(+) (limited to 'Documentation') diff --git a/Documentation/keys.txt b/Documentation/keys.txt index 203487e9b1d..e4dbbdb1bd9 100644 --- a/Documentation/keys.txt +++ b/Documentation/keys.txt @@ -757,6 +757,26 @@ The keyctl syscall functions are: successful. + (*) Install the calling process's session keyring on its parent. + + long keyctl(KEYCTL_SESSION_TO_PARENT); + + This functions attempts to install the calling process's session keyring + on to the calling process's parent, replacing the parent's current session + keyring. + + The calling process must have the same ownership as its parent, the + keyring must have the same ownership as the calling process, the calling + process must have LINK permission on the keyring and the active LSM module + mustn't deny permission, otherwise error EPERM will be returned. + + Error ENOMEM will be returned if there was insufficient memory to complete + the operation, otherwise 0 will be returned to indicate success. + + The keyring will be replaced next time the parent process leaves the + kernel and resumes executing userspace. + + =============== KERNEL SERVICES =============== diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 04e17c1f0f1..d91aaa74705 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -687,5 +687,7 @@ do_notify_resume(struct pt_regs *regs, struct switch_stack *sw, if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 13dec276927..ea4ad3a43c8 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -711,5 +711,7 @@ do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) if (thread_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 62d242e2d03..de9f7fe2aef 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -326,5 +326,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, struct thread_info *ti) if (ti->flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c index 4f06d7fb43d..32e9d5ee895 100644 --- a/arch/cris/kernel/ptrace.c +++ b/arch/cris/kernel/ptrace.c @@ -40,5 +40,7 @@ void do_notify_resume(int canrestart, struct pt_regs *regs, if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 4a7a62c6e78..6b0a2b6fed6 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -572,6 +572,8 @@ asmlinkage void do_notify_resume(__u32 thread_info_flags) if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(__frame); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } /* end do_notify_resume() */ diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index 56b3ab7dbbb..abac3ee8c52 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -556,5 +556,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 5d7c0e5b9e7..89969e95004 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -192,6 +192,8 @@ do_notify_resume_user(sigset_t *unused, struct sigscratch *scr, long in_syscall) if (test_thread_flag(TIF_NOTIFY_RESUME)) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(&scr->pt); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } /* copy user rbs to kernel rbs */ diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index 3220258be18..f80bac17c65 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -411,6 +411,8 @@ void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } clear_thread_flag(TIF_IRET); diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index a3d1015471d..c2acf31874a 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -704,5 +704,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c index feb2f2e810d..a21f43bc68e 100644 --- a/arch/mn10300/kernel/signal.c +++ b/arch/mn10300/kernel/signal.c @@ -568,5 +568,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, u32 thread_info_flags) if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(__frame); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index b3bfc432670..5ca1c02b805 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -649,5 +649,7 @@ void do_notify_resume(struct pt_regs *regs, long in_syscall) if (test_thread_flag(TIF_NOTIFY_RESUME)) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 062bd64e65f..6b4fef877f9 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -536,4 +536,6 @@ void do_notify_resume(struct pt_regs *regs) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index b5afbec1db5..04a21883f32 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -640,5 +640,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0, if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index 0663a0ee602..9e5c9b1d7e9 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c @@ -772,5 +772,7 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned long thread_info if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 181d069a2d4..7ce1a1005b1 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -590,6 +590,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index ec82d76dc6f..647afbda7ae 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -613,5 +613,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } } + diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index 4c578751e94..81e58238c4c 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c @@ -869,6 +869,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) if (thread_info_flags & _TIF_NOTIFY_RESUME) { clear_thread_flag(TIF_NOTIFY_RESUME); tracehook_notify_resume(regs); + if (current->replacement_session_keyring) + key_replace_session_keyring(); } #ifdef CONFIG_X86_32 diff --git a/include/linux/cred.h b/include/linux/cred.h index 85439abdbc8..24520a539c6 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -152,6 +152,7 @@ struct cred { extern void __put_cred(struct cred *); extern void exit_creds(struct task_struct *); extern int copy_creds(struct task_struct *, unsigned long); +extern struct cred *cred_alloc_blank(void); extern struct cred *prepare_creds(void); extern struct cred *prepare_exec_creds(void); extern struct cred *prepare_usermodehelper_creds(void); diff --git a/include/linux/key.h b/include/linux/key.h index 33e0165de10..cd50dfa1d4c 100644 --- a/include/linux/key.h +++ b/include/linux/key.h @@ -278,6 +278,8 @@ static inline key_serial_t key_serial(struct key *key) extern ctl_table key_sysctls[]; #endif +extern void key_replace_session_keyring(void); + /* * the userspace interface */ @@ -300,6 +302,7 @@ extern void key_init(void); #define key_fsuid_changed(t) do { } while(0) #define key_fsgid_changed(t) do { } while(0) #define key_init() do { } while(0) +#define key_replace_session_keyring() do { } while(0) #endif /* CONFIG_KEYS */ #endif /* __KERNEL__ */ diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h index c0688eb7209..bd383f1944f 100644 --- a/include/linux/keyctl.h +++ b/include/linux/keyctl.h @@ -52,5 +52,6 @@ #define KEYCTL_SET_TIMEOUT 15 /* set key timeout */ #define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ #define KEYCTL_GET_SECURITY 17 /* get key security label */ +#define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ #endif /* _LINUX_KEYCTL_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 5c7ce13c169..9304027673b 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1292,6 +1292,7 @@ struct task_struct { struct mutex cred_guard_mutex; /* guard against foreign influences on * credential calculations * (notably. ptrace) */ + struct cred *replacement_session_keyring; /* for KEYCTL_SESSION_TO_PARENT */ char comm[TASK_COMM_LEN]; /* executable name excluding path - access with [gs]et_task_comm (which lock diff --git a/include/linux/security.h b/include/linux/security.h index 40ba39ea68c..97de3fe3dd0 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -653,6 +653,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * manual page for definitions of the @clone_flags. * @clone_flags contains the flags indicating what should be shared. * Return 0 if permission is granted. + * @cred_alloc_blank: + * @cred points to the credentials. + * @gfp indicates the atomicity of any memory allocations. + * Only allocate sufficient memory and attach to @cred such that + * cred_transfer() will not get ENOMEM. * @cred_free: * @cred points to the credentials. * Deallocate and clear the cred->security field in a set of credentials. @@ -665,6 +670,10 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * @new points to the new credentials. * @old points to the original credentials. * Install a new set of credentials. + * @cred_transfer: + * @new points to the new credentials. + * @old points to the original credentials. + * Transfer data from original creds to new creds * @kernel_act_as: * Set the credentials for a kernel service to act as (subjective context). * @new points to the credentials to be modified. @@ -1103,6 +1112,13 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts) * Return the length of the string (including terminating NUL) or -ve if * an error. * May also return 0 (and a NULL buffer pointer) if there is no label. + * @key_session_to_parent: + * Forcibly assign the session keyring from a process to its parent + * process. + * @cred: Pointer to process's credentials + * @parent_cred: Pointer to parent process's credentials + * @keyring: Proposed new session keyring + * Return 0 if permission is granted, -ve error otherwise. * * Security hooks affecting all System V IPC operations. * @@ -1498,10 +1514,12 @@ struct security_operations { int (*dentry_open) (struct file *file, const struct cred *cred); int (*task_create) (unsigned long clone_flags); + int (*cred_alloc_blank) (struct cred *cred, gfp_t gfp); void (*cred_free) (struct cred *cred); int (*cred_prepare)(struct cred *new, const struct cred *old, gfp_t gfp); void (*cred_commit)(struct cred *new, const struct cred *old); + void (*cred_transfer)(struct cred *new, const struct cred *old); int (*kernel_act_as)(struct cred *new, u32 secid); int (*kernel_create_files_as)(struct cred *new, struct inode *inode); int (*kernel_module_request)(void); @@ -1639,6 +1657,9 @@ struct security_operations { const struct cred *cred, key_perm_t perm); int (*key_getsecurity)(struct key *key, char **_buffer); + int (*key_session_to_parent)(const struct cred *cred, + const struct cred *parent_cred, + struct key *key); #endif /* CONFIG_KEYS */ #ifdef CONFIG_AUDIT @@ -1755,9 +1776,11 @@ int security_file_send_sigiotask(struct task_struct *tsk, int security_file_receive(struct file *file); int security_dentry_open(struct file *file, const struct cred *cred); int security_task_create(unsigned long clone_flags); +int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); void security_cred_free(struct cred *cred); int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); void security_commit_creds(struct cred *new, const struct cred *old); +void security_transfer_creds(struct cred *new, const struct cred *old); int security_kernel_act_as(struct cred *new, u32 secid); int security_kernel_create_files_as(struct cred *new, struct inode *inode); int security_kernel_module_request(void); @@ -2286,6 +2309,9 @@ static inline int security_task_create(unsigned long clone_flags) return 0; } +static inline void security_cred_alloc_blank(struct cred *cred, gfp_t gfp) +{ } + static inline void security_cred_free(struct cred *cred) { } @@ -2301,6 +2327,11 @@ static inline void security_commit_creds(struct cred *new, { } +static inline void security_transfer_creds(struct cred *new, + const struct cred *old) +{ +} + static inline int security_kernel_act_as(struct cred *cred, u32 secid) { return 0; @@ -2923,6 +2954,9 @@ void security_key_free(struct key *key); int security_key_permission(key_ref_t key_ref, const struct cred *cred, key_perm_t perm); int security_key_getsecurity(struct key *key, char **_buffer); +int security_key_session_to_parent(const struct cred *cred, + const struct cred *parent_cred, + struct key *key); #else @@ -2950,6 +2984,10 @@ static inline int security_key_getsecurity(struct key *key, char **_buffer) return 0; } +static inline int security_key_session_to_parent(const struct cred *cred, + const struct cred *parent_cred, + struct key *key); + #endif #endif /* CONFIG_KEYS */ diff --git a/kernel/cred.c b/kernel/cred.c index 24dd2f5104b..006fcab009d 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -199,6 +199,49 @@ void exit_creds(struct task_struct *tsk) validate_creds(cred); alter_cred_subscribers(cred, -1); put_cred(cred); + + cred = (struct cred *) tsk->replacement_session_keyring; + if (cred) { + tsk->replacement_session_keyring = NULL; + validate_creds(cred); + put_cred(cred); + } +} + +/* + * Allocate blank credentials, such that the credentials can be filled in at a + * later date without risk of ENOMEM. + */ +struct cred *cred_alloc_blank(void) +{ + struct cred *new; + + new = kmem_cache_zalloc(cred_jar, GFP_KERNEL); + if (!new) + return NULL; + +#ifdef CONFIG_KEYS + new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL); + if (!new->tgcred) { + kfree(new); + return NULL; + } + atomic_set(&new->tgcred->usage, 1); +#endif + + atomic_set(&new->usage, 1); + + if (security_cred_alloc_blank(new, GFP_KERNEL) < 0) + goto error; + +#ifdef CONFIG_DEBUG_CREDENTIALS + new->magic = CRED_MAGIC; +#endif + return new; + +error: + abort_creds(new); + return NULL; } /** diff --git a/security/capability.c b/security/capability.c index 06400cf0775..93a2ffe6590 100644 --- a/security/capability.c +++ b/security/capability.c @@ -373,6 +373,11 @@ static int cap_task_create(unsigned long clone_flags) return 0; } +static int cap_cred_alloc_blank(struct cred *cred, gfp_t gfp) +{ + return 0; +} + static void cap_cred_free(struct cred *cred) { } @@ -386,6 +391,10 @@ static void cap_cred_commit(struct cred *new, const struct cred *old) { } +static void cap_cred_transfer(struct cred *new, const struct cred *old) +{ +} + static int cap_kernel_act_as(struct cred *new, u32 secid) { return 0; @@ -836,6 +845,13 @@ static int cap_key_getsecurity(struct key *key, char **_buffer) return 0; } +static int cap_key_session_to_parent(const struct cred *cred, + const struct cred *parent_cred, + struct key *key) +{ + return 0; +} + #endif /* CONFIG_KEYS */ #ifdef CONFIG_AUDIT @@ -961,9 +977,11 @@ void security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, file_receive); set_to_cap_if_null(ops, dentry_open); set_to_cap_if_null(ops, task_create); + set_to_cap_if_null(ops, cred_alloc_blank); set_to_cap_if_null(ops, cred_free); set_to_cap_if_null(ops, cred_prepare); set_to_cap_if_null(ops, cred_commit); + set_to_cap_if_null(ops, cred_transfer); set_to_cap_if_null(ops, kernel_act_as); set_to_cap_if_null(ops, kernel_create_files_as); set_to_cap_if_null(ops, kernel_module_request); @@ -1063,6 +1081,7 @@ void security_fixup_ops(struct security_operations *ops) set_to_cap_if_null(ops, key_free); set_to_cap_if_null(ops, key_permission); set_to_cap_if_null(ops, key_getsecurity); + set_to_cap_if_null(ops, key_session_to_parent); #endif /* CONFIG_KEYS */ #ifdef CONFIG_AUDIT set_to_cap_if_null(ops, audit_rule_init); diff --git a/security/keys/compat.c b/security/keys/compat.c index c766c68a63b..792c0a611a6 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c @@ -82,6 +82,9 @@ asmlinkage long compat_sys_keyctl(u32 option, case KEYCTL_GET_SECURITY: return keyctl_get_security(arg2, compat_ptr(arg3), arg4); + case KEYCTL_SESSION_TO_PARENT: + return keyctl_session_to_parent(); + default: return -EOPNOTSUPP; } diff --git a/security/keys/gc.c b/security/keys/gc.c index 44adc325e15..1e616aef55f 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c @@ -65,6 +65,7 @@ static void key_gc_timer_func(unsigned long data) * - return true if we altered the keyring */ static bool key_gc_keyring(struct key *keyring, time_t limit) + __releases(key_serial_lock) { struct keyring_list *klist; struct key *key; diff --git a/security/keys/internal.h b/security/keys/internal.h index fb830514c33..24ba0307b7a 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h @@ -201,6 +201,7 @@ extern long keyctl_set_timeout(key_serial_t, unsigned); extern long keyctl_assume_authority(key_serial_t); extern long keyctl_get_security(key_serial_t keyid, char __user *buffer, size_t buflen); +extern long keyctl_session_to_parent(void); /* * debugging key validation diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 736d7800f97..74c96852459 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -1228,6 +1228,105 @@ long keyctl_get_security(key_serial_t keyid, return ret; } +/* + * attempt to install the calling process's session keyring on the process's + * parent process + * - the keyring must exist and must grant us LINK permission + * - implements keyctl(KEYCTL_SESSION_TO_PARENT) + */ +long keyctl_session_to_parent(void) +{ + struct task_struct *me, *parent; + const struct cred *mycred, *pcred; + struct cred *cred, *oldcred; + key_ref_t keyring_r; + int ret; + + keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); + if (IS_ERR(keyring_r)) + return PTR_ERR(keyring_r); + + /* our parent is going to need a new cred struct, a new tgcred struct + * and new security data, so we allocate them here to prevent ENOMEM in + * our parent */ + ret = -ENOMEM; + cred = cred_alloc_blank(); + if (!cred) + goto error_keyring; + + cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); + keyring_r = NULL; + + me = current; + write_lock_irq(&tasklist_lock); + + parent = me->real_parent; + ret = -EPERM; + + /* the parent mustn't be init and mustn't be a kernel thread */ + if (parent->pid <= 1 || !parent->mm) + goto not_permitted; + + /* the parent must be single threaded */ + if (atomic_read(&parent->signal->count) != 1) + goto not_permitted; + + /* the parent and the child must have different session keyrings or + * there's no point */ + mycred = current_cred(); + pcred = __task_cred(parent); + if (mycred == pcred || + mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) + goto already_same; + + /* the parent must have the same effective ownership and mustn't be + * SUID/SGID */ + if (pcred-> uid != mycred->euid || + pcred->euid != mycred->euid || + pcred->suid != mycred->euid || + pcred-> gid != mycred->egid || + pcred->egid != mycred->egid || + pcred->sgid != mycred->egid) + goto not_permitted; + + /* the keyrings must have the same UID */ + if (pcred ->tgcred->session_keyring->uid != mycred->euid || + mycred->tgcred->session_keyring->uid != mycred->euid) + goto not_permitted; + + /* the LSM must permit the replacement of the parent's keyring with the + * keyring from this process */ + ret = security_key_session_to_parent(mycred, pcred, + key_ref_to_ptr(keyring_r)); + if (ret < 0) + goto not_permitted; + + /* if there's an already pending keyring replacement, then we replace + * that */ + oldcred = parent->replacement_session_keyring; + + /* the replacement session keyring is applied just prior to userspace + * restarting */ + parent->replacement_session_keyring = cred; + cred = NULL; + set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); + + write_unlock_irq(&tasklist_lock); + if (oldcred) + put_cred(oldcred); + return 0; + +already_same: + ret = 0; +not_permitted: + put_cred(cred); + return ret; + +error_keyring: + key_ref_put(keyring_r); + return ret; +} + /*****************************************************************************/ /* * the key control system call @@ -1313,6 +1412,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, (char __user *) arg3, (size_t) arg4); + case KEYCTL_SESSION_TO_PARENT: + return keyctl_session_to_parent(); + default: return -EOPNOTSUPP; } diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 4739cfbb41b..5c23afb31ec 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include "internal.h" @@ -768,3 +769,51 @@ error: abort_creds(new); return ret; } + +/* + * Replace a process's session keyring when that process resumes userspace on + * behalf of one of its children + */ +void key_replace_session_keyring(void) +{ + const struct cred *old; + struct cred *new; + + if (!current->replacement_session_keyring) + return; + + write_lock_irq(&tasklist_lock); + new = current->replacement_session_keyring; + current->replacement_session_keyring = NULL; + write_unlock_irq(&tasklist_lock); + + if (!new) + return; + + old = current_cred(); + new-> uid = old-> uid; + new-> euid = old-> euid; + new-> suid = old-> suid; + new->fsuid = old->fsuid; + new-> gid = old-> gid; + new-> egid = old-> egid; + new-> sgid = old-> sgid; + new->fsgid = old->fsgid; + new->user = get_uid(old->user); + new->group_info = get_group_info(old->group_info); + + new->securebits = old->securebits; + new->cap_inheritable = old->cap_inheritable; + new->cap_permitted = old->cap_permitted; + new->cap_effective = old->cap_effective; + new->cap_bset = old->cap_bset; + + new->jit_keyring = old->jit_keyring; + new->thread_keyring = key_get(old->thread_keyring); + new->tgcred->tgid = old->tgcred->tgid; + new->tgcred->process_keyring = key_get(old->tgcred->process_keyring); + + security_transfer_creds(new, old); + + commit_creds(new); +} diff --git a/security/security.c b/security/security.c index f88eaf6b14c..d8b727637f0 100644 --- a/security/security.c +++ b/security/security.c @@ -684,6 +684,11 @@ int security_task_create(unsigned long clone_flags) return security_ops->task_create(clone_flags); } +int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) +{ + return security_ops->cred_alloc_blank(cred, gfp); +} + void security_cred_free(struct cred *cred) { security_ops->cred_free(cred); @@ -699,6 +704,11 @@ void security_commit_creds(struct cred *new, const struct cred *old) security_ops->cred_commit(new, old); } +void security_transfer_creds(struct cred *new, const struct cred *old) +{ + security_ops->cred_transfer(new, old); +} + int security_kernel_act_as(struct cred *new, u32 secid) { return security_ops->kernel_act_as(new, secid); @@ -1241,6 +1251,13 @@ int security_key_getsecurity(struct key *key, char **_buffer) return security_ops->key_getsecurity(key, _buffer); } +int security_key_session_to_parent(const struct cred *cred, + const struct cred *parent_cred, + struct key *key) +{ + return security_ops->key_session_to_parent(cred, parent_cred, key); +} + #endif /* CONFIG_KEYS */ #ifdef CONFIG_AUDIT diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index c3bb31ecc5a..134a9c0d200 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3232,6 +3232,21 @@ static int selinux_task_create(unsigned long clone_flags) return current_has_perm(current, PROCESS__FORK); } +/* + * allocate the SELinux part of blank credentials + */ +static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp) +{ + struct task_security_struct *tsec; + + tsec = kzalloc(sizeof(struct task_security_struct), gfp); + if (!tsec) + return -ENOMEM; + + cred->security = tsec; + return 0; +} + /* * detach and free the LSM part of a set of credentials */ @@ -3263,6 +3278,17 @@ static int selinux_cred_prepare(struct cred *new, const struct cred *old, return 0; } +/* + * transfer the SELinux data to a blank set of creds + */ +static void selinux_cred_transfer(struct cred *new, const struct cred *old) +{ + const struct task_security_struct *old_tsec = old->security; + struct task_security_struct *tsec = new->security; + + *tsec = *old_tsec; +} + /* * set the security data for a kernel service * - all the creation contexts are set to unlabelled @@ -5469,8 +5495,10 @@ static struct security_operations selinux_ops = { .dentry_open = selinux_dentry_open, .task_create = selinux_task_create, + .cred_alloc_blank = selinux_cred_alloc_blank, .cred_free = selinux_cred_free, .cred_prepare = selinux_cred_prepare, + .cred_transfer = selinux_cred_transfer, .kernel_act_as = selinux_kernel_act_as, .kernel_create_files_as = selinux_kernel_create_files_as, .kernel_module_request = selinux_kernel_module_request, diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index c243a2b2583..969f5fee190 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -1079,6 +1079,22 @@ static int smack_file_receive(struct file *file) * Task hooks */ +/** + * smack_cred_alloc_blank - "allocate" blank task-level security credentials + * @new: the new credentials + * @gfp: the atomicity of any memory allocations + * + * Prepare a blank set of credentials for modification. This must allocate all + * the memory the LSM module might require such that cred_transfer() can + * complete without error. + */ +static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) +{ + cred->security = NULL; + return 0; +} + + /** * smack_cred_free - "free" task-level security credentials * @cred: the credentials in question @@ -1116,6 +1132,18 @@ static void smack_cred_commit(struct cred *new, const struct cred *old) { } +/** + * smack_cred_transfer - Transfer the old credentials to the new credentials + * @new: the new credentials + * @old: the original credentials + * + * Fill in a set of blank credentials from another set of credentials. + */ +static void smack_cred_transfer(struct cred *new, const struct cred *old) +{ + new->security = old->security; +} + /** * smack_kernel_act_as - Set the subjective context in a set of credentials * @new: points to the set of credentials to be modified. @@ -3073,9 +3101,11 @@ struct security_operations smack_ops = { .file_send_sigiotask = smack_file_send_sigiotask, .file_receive = smack_file_receive, + .cred_alloc_blank = smack_cred_alloc_blank, .cred_free = smack_cred_free, .cred_prepare = smack_cred_prepare, .cred_commit = smack_cred_commit, + .cred_transfer = smack_cred_transfer, .kernel_act_as = smack_kernel_act_as, .kernel_create_files_as = smack_kernel_create_files_as, .task_setpgid = smack_task_setpgid, diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 35a13e7915e..9548a0984cc 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c @@ -14,6 +14,12 @@ #include "tomoyo.h" #include "realpath.h" +static int tomoyo_cred_alloc_blank(struct cred *new, gfp_t gfp) +{ + new->security = NULL; + return 0; +} + static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, gfp_t gfp) { @@ -25,6 +31,15 @@ static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, return 0; } +static void tomoyo_cred_transfer(struct cred *new, const struct cred *old) +{ + /* + * Since "struct tomoyo_domain_info *" is a sharable pointer, + * we don't need to duplicate. + */ + new->security = old->security; +} + static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) { int rc; @@ -262,7 +277,9 @@ static int tomoyo_dentry_open(struct file *f, const struct cred *cred) */ static struct security_operations tomoyo_security_ops = { .name = "tomoyo", + .cred_alloc_blank = tomoyo_cred_alloc_blank, .cred_prepare = tomoyo_cred_prepare, + .cred_transfer = tomoyo_cred_transfer, .bprm_set_creds = tomoyo_bprm_set_creds, .bprm_check_security = tomoyo_bprm_check_security, #ifdef CONFIG_SYSCTL -- cgit v1.2.3-70-g09d2 From 30681bcf2b15a601b9460e6ddab22077998b8d4c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 3 Sep 2009 16:08:08 +0200 Subject: ALSA: dummy - Add more description Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 4252697a95d..bb488b575de 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -513,6 +513,19 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. or input, but you may use this module for any application which requires a sound card (like RealPlayer). + pcm_devs - Number of PCM devices assigned to each card + (default = 1, up to 4) + pcm_substreams - Number of PCM substreams assigned to each PCM + (default = 8, up to 16) + hrtimer - Use hrtimer (=1, default) or system timer (=0) + + When multiple PCM devices are created, snd-dummy gives different + behavior to each PCM device: + 0 = interleaved with mmap support + 1 = non-interleaved with mmap support + 2 = interleaved without mmap + 3 = non-interleaved without mmap + The power-management is supported. Module snd-echo3g -- cgit v1.2.3-70-g09d2 From 4a88d44ab17da5f8a238050d1b43dfd2e204bc2f Mon Sep 17 00:00:00 2001 From: Albin Tonnerre Date: Mon, 31 Aug 2009 22:40:08 +0200 Subject: tracing: Remove mentioning of legacy latency_trace file from documentation The latency_trace file got removed a while back by commit 886b5b73d71e4027d7dc6c14f5f7ab102201ea6b and has been replaced by the latency-format option. This patch fixes the documentation by reflecting this change. Changes since v1: - mention that the trace format is configurable through the latency-format option - Fix a couple mistakes related to the timestamps Signed-off-by: Albin Tonnerre Cc: Steven Rostedt LKML-Reference: <20090831204007.GE4237@pc-ras4041.res.insa> Signed-off-by: Frederic Weisbecker --- Documentation/trace/ftrace.txt | 68 ++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 32 deletions(-) (limited to 'Documentation') diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt index a39b3c749de..355d0f1f8c5 100644 --- a/Documentation/trace/ftrace.txt +++ b/Documentation/trace/ftrace.txt @@ -85,26 +85,19 @@ of ftrace. Here is a list of some of the key files: This file holds the output of the trace in a human readable format (described below). - latency_trace: - - This file shows the same trace but the information - is organized more to display possible latencies - in the system (described below). - trace_pipe: The output is the same as the "trace" file but this file is meant to be streamed with live tracing. - Reads from this file will block until new data - is retrieved. Unlike the "trace" and "latency_trace" - files, this file is a consumer. This means reading - from this file causes sequential reads to display - more current data. Once data is read from this - file, it is consumed, and will not be read - again with a sequential read. The "trace" and - "latency_trace" files are static, and if the - tracer is not adding more data, they will display - the same information every time they are read. + Reads from this file will block until new data is + retrieved. Unlike the "trace" file, this file is a + consumer. This means reading from this file causes + sequential reads to display more current data. Once + data is read from this file, it is consumed, and + will not be read again with a sequential read. The + "trace" file is static, and if the tracer is not + adding more data,they will display the same + information every time they are read. trace_options: @@ -117,10 +110,10 @@ of ftrace. Here is a list of some of the key files: Some of the tracers record the max latency. For example, the time interrupts are disabled. This time is saved in this file. The max trace - will also be stored, and displayed by either - "trace" or "latency_trace". A new max trace will - only be recorded if the latency is greater than - the value in this file. (in microseconds) + will also be stored, and displayed by "trace". + A new max trace will only be recorded if the + latency is greater than the value in this + file. (in microseconds) buffer_size_kb: @@ -210,7 +203,7 @@ Here is the list of current tracers that may be configured. the trace with the longest max latency. See tracing_max_latency. When a new max is recorded, it replaces the old trace. It is best to view this - trace via the latency_trace file. + trace with the latency-format option enabled. "preemptoff" @@ -307,8 +300,8 @@ the lowest priority thread (pid 0). Latency trace format -------------------- -For traces that display latency times, the latency_trace file -gives somewhat more information to see why a latency happened. +When the latency-format option is enabled, the trace file gives +somewhat more information to see why a latency happened. Here is a typical trace. # tracer: irqsoff @@ -380,9 +373,10 @@ explains which is which. The above is mostly meaningful for kernel developers. - time: This differs from the trace file output. The trace file output - includes an absolute timestamp. The timestamp used by the - latency_trace file is relative to the start of the trace. + time: When the latency-format option is enabled, the trace file + output includes a timestamp relative to the start of the + trace. This differs from the output when latency-format + is disabled, which includes an absolute timestamp. delay: This is just to help catch your eye a bit better. And needs to be fixed to be only relative to the same CPU. @@ -440,7 +434,8 @@ Here are the available options: sym-addr: bash-4000 [01] 1477.606694: simple_strtoul - verbose - This deals with the latency_trace file. + verbose - This deals with the trace file when the + latency-format option is enabled. bash 4000 1 0 00000000 00010a95 [58127d26] 1720.415ms \ (+0.000ms): simple_strtoul (strict_strtoul) @@ -472,7 +467,7 @@ Here are the available options: the app is no longer running The lookup is performed when you read - trace,trace_pipe,latency_trace. Example: + trace,trace_pipe. Example: a.out-1623 [000] 40874.465068: /root/a.out[+0x480] <-/root/a.out[+0 x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6] @@ -481,6 +476,11 @@ x494] <- /root/a.out[+0x4a8] <- /lib/libc-2.7.so[+0x1e1a6] every scheduling event. Will add overhead if there's a lot of tasks running at once. + latency-format - This option changes the trace. When + it is enabled, the trace displays + additional information about the + latencies, as described in "Latency + trace format". sched_switch ------------ @@ -596,12 +596,13 @@ To reset the maximum, echo 0 into tracing_max_latency. Here is an example: # echo irqsoff > current_tracer + # echo latency-format > trace_options # echo 0 > tracing_max_latency # echo 1 > tracing_enabled # ls -ltr [...] # echo 0 > tracing_enabled - # cat latency_trace + # cat trace # tracer: irqsoff # irqsoff latency trace v1.1.5 on 2.6.26 @@ -703,12 +704,13 @@ which preemption was disabled. The control of preemptoff tracer is much like the irqsoff tracer. # echo preemptoff > current_tracer + # echo latency-format > trace_options # echo 0 > tracing_max_latency # echo 1 > tracing_enabled # ls -ltr [...] # echo 0 > tracing_enabled - # cat latency_trace + # cat trace # tracer: preemptoff # preemptoff latency trace v1.1.5 on 2.6.26-rc8 @@ -850,12 +852,13 @@ Again, using this trace is much like the irqsoff and preemptoff tracers. # echo preemptirqsoff > current_tracer + # echo latency-format > trace_options # echo 0 > tracing_max_latency # echo 1 > tracing_enabled # ls -ltr [...] # echo 0 > tracing_enabled - # cat latency_trace + # cat trace # tracer: preemptirqsoff # preemptirqsoff latency trace v1.1.5 on 2.6.26-rc8 @@ -1012,11 +1015,12 @@ Instead of performing an 'ls', we will run 'sleep 1' under 'chrt' which changes the priority of the task. # echo wakeup > current_tracer + # echo latency-format > trace_options # echo 0 > tracing_max_latency # echo 1 > tracing_enabled # chrt -f 5 sleep 1 # echo 0 > tracing_enabled - # cat latency_trace + # cat trace # tracer: wakeup # wakeup latency trace v1.1.5 on 2.6.26-rc8 -- cgit v1.2.3-70-g09d2 From 723884339f90a9c420783135168cc1045750eb5d Mon Sep 17 00:00:00 2001 From: Bhaskar Dutta Date: Thu, 3 Sep 2009 17:25:47 +0530 Subject: sctp: Sysctl configuration for IPv4 Address Scoping This patch introduces a new sysctl option to make IPv4 Address Scoping configurable . In networking environments where DNAT rules in iptables prerouting chains convert destination IP's to link-local/private IP addresses, SCTP connections fail to establish as the INIT chunk is dropped by the kernel due to address scope match failure. For example to support overlapping IP addresses (same IP address with different vlan id) a Layer-5 application listens on link local IP's, and there is a DNAT rule that maps the destination IP to a link local IP. Such applications never get the SCTP INIT if the address-scoping draft is strictly followed. This sysctl configuration allows SCTP to function in such unconventional networking environments. Sysctl options: 0 - Disable IPv4 address scoping draft altogether 1 - Enable IPv4 address scoping (default, current behavior) 2 - Enable address scoping but allow IPv4 private addresses in init/init-ack 3 - Enable address scoping but allow IPv4 link local address in init/init-ack Signed-off-by: Bhaskar Dutta Signed-off-by: Vlad Yasevich --- Documentation/networking/ip-sysctl.txt | 10 ++++++++++ include/net/sctp/constants.h | 7 +++++++ include/net/sctp/structs.h | 10 ++++++++++ net/sctp/bind_addr.c | 21 ++++++++++++++++++++- net/sctp/protocol.c | 11 ++++++----- net/sctp/sysctl.c | 12 ++++++++++++ 6 files changed, 65 insertions(+), 6 deletions(-) (limited to 'Documentation') diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 4e9c6d7b4ef..fbe427a6580 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1297,6 +1297,16 @@ sctp_rmem - vector of 3 INTEGERs: min, default, max sctp_wmem - vector of 3 INTEGERs: min, default, max See tcp_wmem for a description. +addr_scope_policy - INTEGER + Control IPv4 address scoping - draft-stewart-tsvwg-sctp-ipv4-00 + + 0 - Disable IPv4 address scoping + 1 - Enable IPv4 address scoping + 2 - Follow draft but allow IPv4 private addresses + 3 - Follow draft but allow IPv4 link local addresses + + Default: 1 + /proc/sys/net/core/* dev_weight - INTEGER diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index af8c1508109..58f714a3b67 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -363,6 +363,13 @@ typedef enum { SCTP_SCOPE_UNUSABLE, /* IPv4 unusable addresses */ } sctp_scope_t; +typedef enum { + SCTP_SCOPE_POLICY_DISABLE, /* Disable IPv4 address scoping */ + SCTP_SCOPE_POLICY_ENABLE, /* Enable IPv4 address scoping */ + SCTP_SCOPE_POLICY_PRIVATE, /* Follow draft but allow IPv4 private addresses */ + SCTP_SCOPE_POLICY_LINK, /* Follow draft but allow IPv4 link local addresses */ +} sctp_scope_policy_t; + /* Based on IPv4 scoping , * SCTP IPv4 unusable addresses: 0.0.0.0/8, 224.0.0.0/4, 198.18.0.0/24, * 192.88.99.0/24. diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 993cfff9218..a48d80e77cd 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -219,6 +219,15 @@ extern struct sctp_globals { /* Flag to idicate if SCTP-AUTH is enabled */ int auth_enable; + /* + * Policy to control SCTP IPv4 address scoping + * 0 - Disable IPv4 address scoping + * 1 - Enable IPv4 address scoping + * 2 - Selectively allow only IPv4 private addresses + * 3 - Selectively allow only IPv4 link local address + */ + int ipv4_scope_policy; + /* Flag to indicate whether computing and verifying checksum * is disabled. */ int checksum_disable; @@ -252,6 +261,7 @@ extern struct sctp_globals { #define sctp_port_hashtable (sctp_globals.port_hashtable) #define sctp_local_addr_list (sctp_globals.local_addr_list) #define sctp_local_addr_lock (sctp_globals.addr_list_lock) +#define sctp_scope_policy (sctp_globals.ipv4_scope_policy) #define sctp_addip_enable (sctp_globals.addip_enable) #define sctp_addip_noauth (sctp_globals.addip_noauth_enable) #define sctp_prsctp_enable (sctp_globals.prsctp_enable) diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 6d5944a745d..13a6fba4107 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -510,9 +510,28 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope) * of requested destination address, sender and receiver * SHOULD include all of its addresses with level greater * than or equal to L. + * + * Address scoping can be selectively controlled via sysctl + * option */ - if (addr_scope <= scope) + switch (sctp_scope_policy) { + case SCTP_SCOPE_POLICY_DISABLE: return 1; + case SCTP_SCOPE_POLICY_ENABLE: + if (addr_scope <= scope) + return 1; + break; + case SCTP_SCOPE_POLICY_PRIVATE: + if (addr_scope <= scope || SCTP_SCOPE_PRIVATE == addr_scope) + return 1; + break; + case SCTP_SCOPE_POLICY_LINK: + if (addr_scope <= scope || SCTP_SCOPE_LINK == addr_scope) + return 1; + break; + default: + break; + } return 0; } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index a76da657244..60093be8385 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -431,16 +431,14 @@ static int sctp_v4_available(union sctp_addr *addr, struct sctp_sock *sp) * of requested destination address, sender and receiver * SHOULD include all of its addresses with level greater * than or equal to L. + * + * IPv4 scoping can be controlled through sysctl option + * net.sctp.addr_scope_policy */ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr) { sctp_scope_t retval; - /* Should IPv4 scoping be a sysctl configurable option - * so users can turn it off (default on) for certain - * unconventional networking environments? - */ - /* Check for unusable SCTP addresses. */ if (IS_IPV4_UNUSABLE_ADDRESS(addr->v4.sin_addr.s_addr)) { retval = SCTP_SCOPE_UNUSABLE; @@ -1259,6 +1257,9 @@ SCTP_STATIC __init int sctp_init(void) /* Disable AUTH by default. */ sctp_auth_enable = 0; + /* Set SCOPE policy to enabled */ + sctp_scope_policy = SCTP_SCOPE_POLICY_ENABLE; + sctp_sysctl_register(); INIT_LIST_HEAD(&sctp_address_families); diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 63eabbc7129..ab7151da120 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -51,6 +51,7 @@ static int timer_max = 86400000; /* ms in one day */ static int int_max = INT_MAX; static int sack_timer_min = 1; static int sack_timer_max = 500; +static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */ extern int sysctl_sctp_mem[3]; extern int sysctl_sctp_rmem[3]; @@ -272,6 +273,17 @@ static ctl_table sctp_table[] = { .proc_handler = proc_dointvec, .strategy = sysctl_intvec }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "addr_scope_policy", + .data = &sctp_scope_policy, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &zero, + .extra2 = &addr_scope_max, + }, { .ctl_name = 0 } }; -- cgit v1.2.3-70-g09d2 From a65cc60f6349fe91539f736dad8fb2398488e431 Mon Sep 17 00:00:00 2001 From: "ddiaz@cenditel.gob.ve" Date: Sat, 5 Sep 2009 16:28:06 -0430 Subject: ALSA: hda/realtek: Added support for CLEVO M540R subsystem, 6 channel + digital The model clevo-m540r was created with 6-channel and digital support. All functions verified except spdif. Tested with a VIT D2000 laptop which has: [lspci extract] Audio device [0403]: Intel Corporation 82801H (ICH8 Family) HD Audio Controller [8086:284b] (rev 03) Subsystem: CLEVO/KAPOK Computer Device [1558:5409] [/proc/asound/card0/codec\#0 header] Codec: Realtek ALC883 Address: 0 Function Id: 0x1 Vendor Id: 0x10ec0883 Subsystem Id: 0x15585409 Revision Id: 0x100002 [Added a comment about HP mute and the model description by tiwai] Signed-off-by: Dhionel Diaz Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/HD-Audio-Models.txt | 1 + sound/pci/hda/patch_realtek.c | 80 ++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 32d8cc05d15..97eebd63bed 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt @@ -152,6 +152,7 @@ ALC882/883/885/888/889 3stack-hp HP machines with 3stack (Lucknow, Samba boards) 6stack-dell Dell machines with 6stack (Inspiron 530) mitac Mitac 8252D + clevo-m540r Clevo M540R (6ch + digital) clevo-m720 Clevo M720 laptop series fujitsu-pi2515 Fujitsu AMILO Pi2515 fujitsu-xa3530 Fujitsu AMILO XA3530 diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f3d186a1e3d..e58d4c5d6c1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -232,6 +232,7 @@ enum { ALC888_3ST_HP, ALC888_6ST_DELL, ALC883_MITAC, + ALC883_CLEVO_M540R, ALC883_CLEVO_M720, ALC883_FUJITSU_PI2515, ALC888_FUJITSU_XA3530, @@ -6656,6 +6657,52 @@ static struct hda_channel_mode alc882_3ST_6ch_modes[3] = { #define alc883_3ST_6ch_modes alc882_3ST_6ch_modes +/* + * 2ch mode + */ +static struct hda_verb alc883_3ST_ch2_clevo_init[] = { + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { } /* end */ +}; + +/* + * 4ch mode + */ +static struct hda_verb alc883_3ST_ch4_clevo_init[] = { + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +/* + * 6ch mode + */ +static struct hda_verb alc883_3ST_ch6_clevo_init[] = { + { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, + { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, + { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, + { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, + { } /* end */ +}; + +static struct hda_channel_mode alc883_3ST_6ch_clevo_modes[3] = { + { 2, alc883_3ST_ch2_clevo_init }, + { 4, alc883_3ST_ch4_clevo_init }, + { 6, alc883_3ST_ch6_clevo_init }, +}; + + /* * 6ch mode */ @@ -8134,6 +8181,22 @@ static struct hda_verb alc883_mitac_verbs[] = { { } /* end */ }; +static struct hda_verb alc883_clevo_m540r_verbs[] = { + /* HP */ + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + /* Int speaker */ + /*{0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},*/ + + /* enable unsolicited event */ + /* + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_MIC_EVENT | AC_USRSP_EN}, + */ + + { } /* end */ +}; + static struct hda_verb alc883_clevo_m720_verbs[] = { /* HP */ {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -8670,6 +8733,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC888_3ST_HP] = "3stack-hp", [ALC888_6ST_DELL] = "6stack-dell", [ALC883_MITAC] = "mitac", + [ALC883_CLEVO_M540R] = "clevo-m540r", [ALC883_CLEVO_M720] = "clevo-m720", [ALC883_FUJITSU_PI2515] = "fujitsu-pi2515", [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", @@ -8776,6 +8840,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x147b, 0x1083, "Abit IP35-PRO", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1558, 0x0721, "Clevo laptop M720R", ALC883_CLEVO_M720), SND_PCI_QUIRK(0x1558, 0x0722, "Clevo laptop M720SR", ALC883_CLEVO_M720), + SND_PCI_QUIRK(0x1558, 0x5409, "Clevo laptop M540R", ALC883_CLEVO_M540R), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC883_LAPTOP_EAPD), SND_PCI_QUIRK(0x15d9, 0x8780, "Supermicro PDSBA", ALC883_3ST_6ch), /* SND_PCI_QUIRK(0x161f, 0x2054, "Arima W820", ALC882_ARIMA), */ @@ -9264,6 +9329,21 @@ static struct alc_config_preset alc882_presets[] = { .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_capture_source, }, + [ALC883_CLEVO_M540R] = { + .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, + .init_verbs = { alc883_init_verbs, alc883_clevo_m540r_verbs }, + .num_dacs = ARRAY_SIZE(alc883_dac_nids), + .dac_nids = alc883_dac_nids, + .dig_out_nid = ALC883_DIGOUT_NID, + .dig_in_nid = ALC883_DIGIN_NID, + .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_clevo_modes), + .channel_mode = alc883_3ST_6ch_clevo_modes, + .need_dac_fix = 1, + .input_mux = &alc883_capture_source, + /* This machine has the hardware HP auto-muting, thus + * we need no software mute via unsol event + */ + }, [ALC883_CLEVO_M720] = { .mixers = { alc883_clevo_m720_mixer }, .init_verbs = { alc883_init_verbs, alc883_clevo_m720_verbs }, -- cgit v1.2.3-70-g09d2 From a68c4d11336610dc348620766119db09675707c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 4 Sep 2009 12:19:36 +0200 Subject: ALSA: dummy - Fake buffer allocations Instead of allocating the real buffers, use a fake buffer and ignore read/write in the dummy driver so that we can save the resources. For mmap, a single page (unique to the direction, though) is reused to all buffers. When the app requires to read/write the real buffers, pass fake_buffer=0 module option at loading time. This will get back to the old behavior. Signed-off-by: Takashi Iwai --- Documentation/sound/alsa/ALSA-Configuration.txt | 7 ++ sound/drivers/dummy.c | 106 ++++++++++++++++++++++-- 2 files changed, 105 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index bb488b575de..ea16e7d184a 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt @@ -518,6 +518,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. pcm_substreams - Number of PCM substreams assigned to each PCM (default = 8, up to 16) hrtimer - Use hrtimer (=1, default) or system timer (=0) + fake_buffer - Fake buffer allocations (default = 1) When multiple PCM devices are created, snd-dummy gives different behavior to each PCM device: @@ -526,6 +527,12 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. 2 = interleaved without mmap 3 = non-interleaved without mmap + As default, snd-dummy drivers doesn't allocate the real buffers + but either ignores read/write or mmap a single dummy page to all + buffer pages, in order to save the resouces. If your apps need + the read/ written buffer data to be consistent, pass fake_buffer=0 + option. + The power-management is supported. Module snd-echo3g diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index e8e29bfb85e..2ee6c8ebe25 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -153,6 +153,7 @@ static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; #ifdef CONFIG_HIGH_RES_TIMERS static int hrtimer = 1; #endif +static int fake_buffer = 1; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for dummy soundcard."); @@ -166,6 +167,8 @@ module_param_array(pcm_substreams, int, NULL, 0444); MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver."); //module_param_array(midi_devs, int, NULL, 0444); //MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver."); +module_param(fake_buffer, bool, 0444); +MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations."); #ifdef CONFIG_HIGH_RES_TIMERS module_param(hrtimer, bool, 0644); MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source."); @@ -481,11 +484,8 @@ static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) static int dummy_pcm_prepare(struct snd_pcm_substream *substream) { - struct snd_pcm_runtime *runtime = substream->runtime; struct snd_dummy *dummy = snd_pcm_substream_chip(substream); - snd_pcm_format_set_silence(runtime->format, runtime->dma_area, - bytes_to_samples(runtime, runtime->dma_bytes)); return dummy->timer_ops->prepare(substream); } @@ -518,12 +518,19 @@ static struct snd_pcm_hardware dummy_pcm_hardware = { static int dummy_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { + if (fake_buffer) { + /* runtime->dma_bytes has to be set manually to allow mmap */ + substream->runtime->dma_bytes = params_buffer_bytes(hw_params); + return 0; + } return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } static int dummy_pcm_hw_free(struct snd_pcm_substream *substream) { + if (fake_buffer) + return 0; return snd_pcm_lib_free_pages(substream); } @@ -570,6 +577,60 @@ static int dummy_pcm_close(struct snd_pcm_substream *substream) return 0; } +/* + * dummy buffer handling + */ + +static void *dummy_page[2]; + +static void free_fake_buffer(void) +{ + if (fake_buffer) { + int i; + for (i = 0; i < 2; i++) + if (dummy_page[i]) { + free_page((unsigned long)dummy_page[i]); + dummy_page[i] = NULL; + } + } +} + +static int alloc_fake_buffer(void) +{ + int i; + + if (!fake_buffer) + return 0; + for (i = 0; i < 2; i++) { + dummy_page[i] = (void *)get_zeroed_page(GFP_KERNEL); + if (!dummy_page[i]) { + free_fake_buffer(); + return -ENOMEM; + } + } + return 0; +} + +static int dummy_pcm_copy(struct snd_pcm_substream *substream, + int channel, snd_pcm_uframes_t pos, + void __user *dst, snd_pcm_uframes_t count) +{ + return 0; /* do nothing */ +} + +static int dummy_pcm_silence(struct snd_pcm_substream *substream, + int channel, snd_pcm_uframes_t pos, + snd_pcm_uframes_t count) +{ + return 0; /* do nothing */ +} + +static struct page *dummy_pcm_page(struct snd_pcm_substream *substream, + unsigned long offset) +{ + return virt_to_page(dummy_page[substream->stream]); /* the same page */ +} + static struct snd_pcm_ops dummy_pcm_ops = { .open = dummy_pcm_open, .close = dummy_pcm_close, @@ -581,10 +642,25 @@ static struct snd_pcm_ops dummy_pcm_ops = { .pointer = dummy_pcm_pointer, }; +static struct snd_pcm_ops dummy_pcm_ops_no_buf = { + .open = dummy_pcm_open, + .close = dummy_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = dummy_pcm_hw_params, + .hw_free = dummy_pcm_hw_free, + .prepare = dummy_pcm_prepare, + .trigger = dummy_pcm_trigger, + .pointer = dummy_pcm_pointer, + .copy = dummy_pcm_copy, + .silence = dummy_pcm_silence, + .page = dummy_pcm_page, +}; + static int __devinit snd_card_dummy_pcm(struct snd_dummy *dummy, int device, int substreams) { struct snd_pcm *pcm; + struct snd_pcm_ops *ops; int err; err = snd_pcm_new(dummy->card, "Dummy PCM", device, @@ -592,14 +668,21 @@ static int __devinit snd_card_dummy_pcm(struct snd_dummy *dummy, int device, if (err < 0) return err; dummy->pcm = pcm; - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &dummy_pcm_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &dummy_pcm_ops); + if (fake_buffer) + ops = &dummy_pcm_ops_no_buf; + else + ops = &dummy_pcm_ops; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, ops); pcm->private_data = dummy; pcm->info_flags = 0; strcpy(pcm->name, "Dummy PCM"); - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, - snd_dma_continuous_data(GFP_KERNEL), - 0, 64*1024); + if (!fake_buffer) { + snd_pcm_lib_preallocate_pages_for_all(pcm, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 0, 64*1024); + } return 0; } @@ -822,6 +905,7 @@ static void snd_dummy_unregister_all(void) for (i = 0; i < ARRAY_SIZE(devices); ++i) platform_device_unregister(devices[i]); platform_driver_unregister(&snd_dummy_driver); + free_fake_buffer(); } static int __init alsa_card_dummy_init(void) @@ -832,6 +916,12 @@ static int __init alsa_card_dummy_init(void) if (err < 0) return err; + err = alloc_fake_buffer(); + if (err < 0) { + platform_driver_unregister(&snd_dummy_driver); + return err; + } + cards = 0; for (i = 0; i < SNDRV_CARDS; i++) { struct platform_device *device; -- cgit v1.2.3-70-g09d2 From 30b3710105be0ba6bbdb7d7d126af76246b02eba Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Fri, 4 Sep 2009 17:44:51 -0700 Subject: kmemleak: add clear command support In an ideal world your kmemleak output will be small, when its not (usually during initial bootup) you can use the clear command to ingore previously reported and unreferenced kmemleak objects. We do this by painting all currently reported unreferenced objects grey. We paint them grey instead of black to allow future scans on the same objects as such objects could still potentially reference newly allocated objects in the future. To test a critical section on demand with a clean /sys/kernel/debug/kmemleak you can do: echo clear > /sys/kernel/debug/kmemleak test your kernel or modules echo scan > /sys/kernel/debug/kmemleak Then as usual to get your report with: cat /sys/kernel/debug/kmemleak Signed-off-by: Luis R. Rodriguez Signed-off-by: Catalin Marinas --- Documentation/kmemleak.txt | 30 ++++++++++++++++++++++++++++++ mm/kmemleak.c | 26 ++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kmemleak.txt b/Documentation/kmemleak.txt index c223785339b..34f6638aa5a 100644 --- a/Documentation/kmemleak.txt +++ b/Documentation/kmemleak.txt @@ -27,6 +27,13 @@ To trigger an intermediate memory scan: # echo scan > /sys/kernel/debug/kmemleak +To clear the list of all current possible memory leaks: + + # echo clear > /sys/kernel/debug/kmemleak + +New leaks will then come up upon reading /sys/kernel/debug/kmemleak +again. + Note that the orphan objects are listed in the order they were allocated and one object at the beginning of the list may cause other subsequent objects to be reported as orphan. @@ -42,6 +49,8 @@ Memory scanning parameters can be modified at run-time by writing to the scan= - set the automatic memory scanning period in seconds (default 600, 0 to stop the automatic scanning) scan - trigger a memory scan + clear - clear list of current memory leak suspects, done by + marking all current reported unreferenced objects grey dump= - dump information about the object found at Kmemleak can also be disabled at boot-time by passing "kmemleak=off" on @@ -87,6 +96,27 @@ avoid this, kmemleak can also store the number of values pointing to an address inside the block address range that need to be found so that the block is not considered a leak. One example is __vmalloc(). +Testing specific sections with kmemleak +--------------------------------------- + +Upon initial bootup your /sys/kernel/debug/kmemleak output page may be +quite extensive. This can also be the case if you have very buggy code +when doing development. To work around these situations you can use the +'clear' command to clear all reported unreferenced objects from the +/sys/kernel/debug/kmemleak output. By issuing a 'scan' after a 'clear' +you can find new unreferenced objects; this should help with testing +specific sections of code. + +To test a critical section on demand with a clean kmemleak do: + + # echo clear > /sys/kernel/debug/kmemleak + ... test your kernel or modules ... + # echo scan > /sys/kernel/debug/kmemleak + +Then as usual to get your report with: + + # cat /sys/kernel/debug/kmemleak + Kmemleak API ------------ diff --git a/mm/kmemleak.c b/mm/kmemleak.c index f5042b4a7b9..c17dbc76fb7 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1420,6 +1420,28 @@ static int dump_str_object_info(const char *str) return 0; } +/* + * We use grey instead of black to ensure we can do future scans on the same + * objects. If we did not do future scans these black objects could + * potentially contain references to newly allocated objects in the future and + * we'd end up with false positives. + */ +static void kmemleak_clear(void) +{ + struct kmemleak_object *object; + unsigned long flags; + + rcu_read_lock(); + list_for_each_entry_rcu(object, &object_list, object_list) { + spin_lock_irqsave(&object->lock, flags); + if ((object->flags & OBJECT_REPORTED) && + unreferenced_object(object)) + object->min_count = 0; + spin_unlock_irqrestore(&object->lock, flags); + } + rcu_read_unlock(); +} + /* * File write operation to configure kmemleak at run-time. The following * commands can be written to the /sys/kernel/debug/kmemleak file: @@ -1431,6 +1453,8 @@ static int dump_str_object_info(const char *str) * scan=... - set the automatic memory scanning period in seconds (0 to * disable it) * scan - trigger a memory scan + * clear - mark all current reported unreferenced kmemleak objects as + * grey to ignore printing them * dump=... - dump information about the object found at the given address */ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf, @@ -1472,6 +1496,8 @@ static ssize_t kmemleak_write(struct file *file, const char __user *user_buf, } } else if (strncmp(buf, "scan", 4) == 0) kmemleak_scan(); + else if (strncmp(buf, "clear", 5) == 0) + kmemleak_clear(); else if (strncmp(buf, "dump=", 5) == 0) ret = dump_str_object_info(buf + 5); else -- cgit v1.2.3-70-g09d2 From 4d8cd26849737e141ff0aa23fedacef4ea76ea4f Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 8 Sep 2009 12:09:47 -0700 Subject: wireless: mark prism54 as deprecated and mark for removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The preferred module is p54pci which also supports FullMAC PCI / Cardbus devices. We schedule removal for 2.6.34. Reason to remove this is no one really is testing prism54 anymore, and while it works p54pci provides support for the same hardware. It should be noted I have been told some FullMAC devices may not have worked with the SoftMAC driver but to date we have yet to recieve a single bug report regarding this. If there are users out there please let us know! Cc: aquilaver@yahoo.com Cc: linux-kernel@vger.kernel.org Cc: Dan Williams Cc: Kai Engert Cc: Jean Tourrilhes Cc: Tim de Waal Cc: Roy Marples Cc: Alan Cox Cc: Christian Lamparter Cc: Björn Steinbrink Cc: Tim Gardner Cc: Larry Finger Cc: Johannes Berg Signed-off-by: Luis R. Rodriguez Signed-off-by: John W. Linville --- Documentation/feature-removal-schedule.txt | 29 +++++++++++++++ drivers/net/wireless/Kconfig | 57 +++++++++--------------------- 2 files changed, 45 insertions(+), 41 deletions(-) (limited to 'Documentation') diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 09e031c5588..ad522e3d3d8 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -6,6 +6,35 @@ be removed from this file. --------------------------- +What: PRISM54 +When: 2.6.34 + +Why: prism54 FullMAC PCI / Cardbus devices used to be supported only by the + prism54 wireless driver. After Intersil stopped selling these + devices in preference for the newer more flexible SoftMAC devices + a SoftMAC device driver was required and prism54 did not support + them. The p54pci driver now exists and has been present in the kernel for + a while. This driver supports both SoftMAC devices and FullMAC devices. + The main difference between these devices was the amount of memory which + could be used for the firmware. The SoftMAC devices support a smaller + amount of memory. Because of this the SoftMAC firmware fits into FullMAC + devices's memory. p54pci supports not only PCI / Cardbus but also USB + and SPI. Since p54pci supports all devices prism54 supports + you will have a conflict. I'm not quite sure how distributions are + handling this conflict right now. prism54 was kept around due to + claims users may experience issues when using the SoftMAC driver. + Time has passed users have not reported issues. If you use prism54 + and for whatever reason you cannot use p54pci please let us know! + E-mail us at: linux-wireless@vger.kernel.org + + For more information see the p54 wiki page: + + http://wireless.kernel.org/en/users/Drivers/p54 + +Who: Luis R. Rodriguez + +--------------------------- + What: IRQF_SAMPLE_RANDOM Check: IRQF_SAMPLE_RANDOM When: July 2009 diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index a8871a84d87..ad89d23968d 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -275,51 +275,26 @@ config PCMCIA_WL3501 micro support for ethtool. config PRISM54 - tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus' + tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)' depends on PCI && EXPERIMENTAL && WLAN_80211 select WIRELESS_EXT select FW_LOADER ---help--- - Enable PCI and Cardbus support for the following chipset based cards: - - ISL3880 - Prism GT 802.11 b/g - ISL3877 - Prism Indigo 802.11 a - ISL3890 - Prism Duette 802.11 a/b/g - - For a complete list of supported cards visit . - Here is the latest confirmed list of supported cards: - - 3com OfficeConnect 11g Cardbus Card aka 3CRWE154G72 (version 1) - Allnet ALL0271 PCI Card - Compex WL54G Cardbus Card - Corega CG-WLCB54GT Cardbus Card - D-Link Air Plus Xtreme G A1 Cardbus Card aka DWL-g650 - I-O Data WN-G54/CB Cardbus Card - Kobishi XG-300 aka Z-Com Cardbus Card - Netgear WG511 Cardbus Card - Ovislink WL-5400PCI PCI Card - Peabird WLG-PCI PCI Card - Sitecom WL-100i Cardbus Card - Sitecom WL-110i PCI Card - SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card - SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card - SMC2835W-V2 - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card - Z-Com XG-900 PCI Card - Zyxel G-100 Cardbus Card - - If you enable this you will need a firmware file as well. - You will need to copy this to /usr/lib/hotplug/firmware/isl3890. - You can get this non-GPL'd firmware file from the Prism54 project page: - - You will also need the /etc/hotplug/firmware.agent script from - a current hotplug package. - - Note: You need a motherboard with DMA support to use any of these cards - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . - The module will be called prism54. + This enables support for FullMAC PCI/Cardbus prism54 devices. This + driver is now deprecated in favor for the SoftMAC driver, p54pci. + p54pci supports FullMAC PCI/Cardbus devices as well. For details on + the scheduled removal of this driver on the kernel see the feature + removal schedule: + + Documentation/feature-removal-schedule.txt + + For more information refer to the p54 wiki: + + http://wireless.kernel.org/en/users/Drivers/p54 + + Note: You need a motherboard with DMA support to use any of these cards + + When built as module you get the module prism54 config USB_ZD1201 tristate "USB ZD1201 based Wireless device support" -- cgit v1.2.3-70-g09d2 From 9c1b96e34717d001873b603d85434aa78e730282 Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Tue, 9 Jun 2009 12:37:58 +0300 Subject: KVM: Document basic API Document the basic API corresponding to the 2.6.22 release. Signed-off-by: Avi Kivity --- Documentation/kvm/api.txt | 683 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 683 insertions(+) create mode 100644 Documentation/kvm/api.txt (limited to 'Documentation') diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt new file mode 100644 index 00000000000..1b1c22da211 --- /dev/null +++ b/Documentation/kvm/api.txt @@ -0,0 +1,683 @@ +The Definitive KVM (Kernel-based Virtual Machine) API Documentation +=================================================================== + +1. General description + +The kvm API is a set of ioctls that are issued to control various aspects +of a virtual machine. The ioctls belong to three classes + + - System ioctls: These query and set global attributes which affect the + whole kvm subsystem. In addition a system ioctl is used to create + virtual machines + + - VM ioctls: These query and set attributes that affect an entire virtual + machine, for example memory layout. In addition a VM ioctl is used to + create virtual cpus (vcpus). + + Only run VM ioctls from the same process (address space) that was used + to create the VM. + + - vcpu ioctls: These query and set attributes that control the operation + of a single virtual cpu. + + Only run vcpu ioctls from the same thread that was used to create the + vcpu. + +2. File descritpors + +The kvm API is centered around file descriptors. An initial +open("/dev/kvm") obtains a handle to the kvm subsystem; this handle +can be used to issue system ioctls. A KVM_CREATE_VM ioctl on this +handle will create a VM file descripror which can be used to issue VM +ioctls. A KVM_CREATE_VCPU ioctl on a VM fd will create a virtual cpu +and return a file descriptor pointing to it. Finally, ioctls on a vcpu +fd can be used to control the vcpu, including the important task of +actually running guest code. + +In general file descriptors can be migrated among processes by means +of fork() and the SCM_RIGHTS facility of unix domain socket. These +kinds of tricks are explicitly not supported by kvm. While they will +not cause harm to the host, their actual behavior is not guaranteed by +the API. The only supported use is one virtual machine per process, +and one vcpu per thread. + +3. Extensions + +As of Linux 2.6.22, the KVM ABI has been stabilized: no backward +incompatible change are allowed. However, there is an extension +facility that allows backward-compatible extensions to the API to be +queried and used. + +The extension mechanism is not based on on the Linux version number. +Instead, kvm defines extension identifiers and a facility to query +whether a particular extension identifier is available. If it is, a +set of ioctls is available for application use. + +4. API description + +This section describes ioctls that can be used to control kvm guests. +For each ioctl, the following information is provided along with a +description: + + Capability: which KVM extension provides this ioctl. Can be 'basic', + which means that is will be provided by any kernel that supports + API version 12 (see section 4.1), or a KVM_CAP_xyz constant, which + means availability needs to be checked with KVM_CHECK_EXTENSION + (see section 4.4). + + Architectures: which instruction set architectures provide this ioctl. + x86 includes both i386 and x86_64. + + Type: system, vm, or vcpu. + + Parameters: what parameters are accepted by the ioctl. + + Returns: the return value. General error numbers (EBADF, ENOMEM, EINVAL) + are not detailed, but errors with specific meanings are. + +4.1 KVM_GET_API_VERSION + +Capability: basic +Architectures: all +Type: system ioctl +Parameters: none +Returns: the constant KVM_API_VERSION (=12) + +This identifies the API version as the stable kvm API. It is not +expected that this number will change. However, Linux 2.6.20 and +2.6.21 report earlier versions; these are not documented and not +supported. Applications should refuse to run if KVM_GET_API_VERSION +returns a value other than 12. If this check passes, all ioctls +described as 'basic' will be available. + +4.2 KVM_CREATE_VM + +Capability: basic +Architectures: all +Type: system ioctl +Parameters: none +Returns: a VM fd that can be used to control the new virtual machine. + +The new VM has no virtual cpus and no memory. An mmap() of a VM fd +will access the virtual machine's physical address space; offset zero +corresponds to guest physical address zero. Use of mmap() on a VM fd +is discouraged if userspace memory allocation (KVM_CAP_USER_MEMORY) is +available. + +4.3 KVM_GET_MSR_INDEX_LIST + +Capability: basic +Architectures: x86 +Type: system +Parameters: struct kvm_msr_list (in/out) +Returns: 0 on success; -1 on error +Errors: + E2BIG: the msr index list is to be to fit in the array specified by + the user. + +struct kvm_msr_list { + __u32 nmsrs; /* number of msrs in entries */ + __u32 indices[0]; +}; + +This ioctl returns the guest msrs that are supported. The list varies +by kvm version and host processor, but does not change otherwise. The +user fills in the size of the indices array in nmsrs, and in return +kvm adjusts nmsrs to reflect the actual number of msrs and fills in +the indices array with their numbers. + +4.4 KVM_CHECK_EXTENSION + +Capability: basic +Architectures: all +Type: system ioctl +Parameters: extension identifier (KVM_CAP_*) +Returns: 0 if unsupported; 1 (or some other positive integer) if supported + +The API allows the application to query about extensions to the core +kvm API. Userspace passes an extension identifier (an integer) and +receives an integer that describes the extension availability. +Generally 0 means no and 1 means yes, but some extensions may report +additional information in the integer return value. + +4.5 KVM_GET_VCPU_MMAP_SIZE + +Capability: basic +Architectures: all +Type: system ioctl +Parameters: none +Returns: size of vcpu mmap area, in bytes + +The KVM_RUN ioctl (cf.) communicates with userspace via a shared +memory region. This ioctl returns the size of that region. See the +KVM_RUN documentation for details. + +4.6 KVM_SET_MEMORY_REGION + +Capability: basic +Architectures: all +Type: vm ioctl +Parameters: struct kvm_memory_region (in) +Returns: 0 on success, -1 on error + +struct kvm_memory_region { + __u32 slot; + __u32 flags; + __u64 guest_phys_addr; + __u64 memory_size; /* bytes */ +}; + +/* for kvm_memory_region::flags */ +#define KVM_MEM_LOG_DIRTY_PAGES 1UL + +This ioctl allows the user to create or modify a guest physical memory +slot. When changing an existing slot, it may be moved in the guest +physical memory space, or its flags may be modified. It may not be +resized. Slots may not overlap. + +The flags field supports just one flag, KVM_MEM_LOG_DIRTY_PAGES, which +instructs kvm to keep track of writes to memory within the slot. See +the KVM_GET_DIRTY_LOG ioctl. + +It is recommended to use the KVM_SET_USER_MEMORY_REGION ioctl instead +of this API, if available. This newer API allows placing guest memory +at specified locations in the host address space, yielding better +control and easy access. + +4.6 KVM_CREATE_VCPU + +Capability: basic +Architectures: all +Type: vm ioctl +Parameters: vcpu id (apic id on x86) +Returns: vcpu fd on success, -1 on error + +This API adds a vcpu to a virtual machine. The vcpu id is a small integer +in the range [0, max_vcpus). + +4.7 KVM_GET_DIRTY_LOG (vm ioctl) + +Capability: basic +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_dirty_log (in/out) +Returns: 0 on success, -1 on error + +/* for KVM_GET_DIRTY_LOG */ +struct kvm_dirty_log { + __u32 slot; + __u32 padding; + union { + void __user *dirty_bitmap; /* one bit per page */ + __u64 padding; + }; +}; + +Given a memory slot, return a bitmap containing any pages dirtied +since the last call to this ioctl. Bit 0 is the first page in the +memory slot. Ensure the entire structure is cleared to avoid padding +issues. + +4.8 KVM_SET_MEMORY_ALIAS + +Capability: basic +Architectures: x86 +Type: vm ioctl +Parameters: struct kvm_memory_alias (in) +Returns: 0 (success), -1 (error) + +struct kvm_memory_alias { + __u32 slot; /* this has a different namespace than memory slots */ + __u32 flags; + __u64 guest_phys_addr; + __u64 memory_size; + __u64 target_phys_addr; +}; + +Defines a guest physical address space region as an alias to another +region. Useful for aliased address, for example the VGA low memory +window. Should not be used with userspace memory. + +4.9 KVM_RUN + +Capability: basic +Architectures: all +Type: vcpu ioctl +Parameters: none +Returns: 0 on success, -1 on error +Errors: + EINTR: an unmasked signal is pending + +This ioctl is used to run a guest virtual cpu. While there are no +explicit parameters, there is an implicit parameter block that can be +obtained by mmap()ing the vcpu fd at offset 0, with the size given by +KVM_GET_VCPU_MMAP_SIZE. The parameter block is formatted as a 'struct +kvm_run' (see below). + +4.10 KVM_GET_REGS + +Capability: basic +Architectures: all +Type: vcpu ioctl +Parameters: struct kvm_regs (out) +Returns: 0 on success, -1 on error + +Reads the general purpose registers from the vcpu. + +/* x86 */ +struct kvm_regs { + /* out (KVM_GET_REGS) / in (KVM_SET_REGS) */ + __u64 rax, rbx, rcx, rdx; + __u64 rsi, rdi, rsp, rbp; + __u64 r8, r9, r10, r11; + __u64 r12, r13, r14, r15; + __u64 rip, rflags; +}; + +4.11 KVM_SET_REGS + +Capability: basic +Architectures: all +Type: vcpu ioctl +Parameters: struct kvm_regs (in) +Returns: 0 on success, -1 on error + +Writes the general purpose registers into the vcpu. + +See KVM_GET_REGS for the data structure. + +4.12 KVM_GET_SREGS + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_sregs (out) +Returns: 0 on success, -1 on error + +Reads special registers from the vcpu. + +/* x86 */ +struct kvm_sregs { + struct kvm_segment cs, ds, es, fs, gs, ss; + struct kvm_segment tr, ldt; + struct kvm_dtable gdt, idt; + __u64 cr0, cr2, cr3, cr4, cr8; + __u64 efer; + __u64 apic_base; + __u64 interrupt_bitmap[(KVM_NR_INTERRUPTS + 63) / 64]; +}; + +interrupt_bitmap is a bitmap of pending external interrupts. At most +one bit may be set. This interrupt has been acknowledged by the APIC +but not yet injected into the cpu core. + +4.13 KVM_SET_SREGS + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_sregs (in) +Returns: 0 on success, -1 on error + +Writes special registers into the vcpu. See KVM_GET_SREGS for the +data structures. + +4.14 KVM_TRANSLATE + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_translation (in/out) +Returns: 0 on success, -1 on error + +Translates a virtual address according to the vcpu's current address +translation mode. + +struct kvm_translation { + /* in */ + __u64 linear_address; + + /* out */ + __u64 physical_address; + __u8 valid; + __u8 writeable; + __u8 usermode; + __u8 pad[5]; +}; + +4.15 KVM_INTERRUPT + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_interrupt (in) +Returns: 0 on success, -1 on error + +Queues a hardware interrupt vector to be injected. This is only +useful if in-kernel local APIC is not used. + +/* for KVM_INTERRUPT */ +struct kvm_interrupt { + /* in */ + __u32 irq; +}; + +Note 'irq' is an interrupt vector, not an interrupt pin or line. + +4.16 KVM_DEBUG_GUEST + +Capability: basic +Architectures: none +Type: vcpu ioctl +Parameters: none) +Returns: -1 on error + +Support for this has been removed. Use KVM_SET_GUEST_DEBUG instead. + +4.17 KVM_GET_MSRS + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_msrs (in/out) +Returns: 0 on success, -1 on error + +Reads model-specific registers from the vcpu. Supported msr indices can +be obtained using KVM_GET_MSR_INDEX_LIST. + +struct kvm_msrs { + __u32 nmsrs; /* number of msrs in entries */ + __u32 pad; + + struct kvm_msr_entry entries[0]; +}; + +struct kvm_msr_entry { + __u32 index; + __u32 reserved; + __u64 data; +}; + +Application code should set the 'nmsrs' member (which indicates the +size of the entries array) and the 'index' member of each array entry. +kvm will fill in the 'data' member. + +4.18 KVM_SET_MSRS + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_msrs (in) +Returns: 0 on success, -1 on error + +Writes model-specific registers to the vcpu. See KVM_GET_MSRS for the +data structures. + +Application code should set the 'nmsrs' member (which indicates the +size of the entries array), and the 'index' and 'data' members of each +array entry. + +4.19 KVM_SET_CPUID + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_cpuid (in) +Returns: 0 on success, -1 on error + +Defines the vcpu responses to the cpuid instruction. Applications +should use the KVM_SET_CPUID2 ioctl if available. + + +struct kvm_cpuid_entry { + __u32 function; + __u32 eax; + __u32 ebx; + __u32 ecx; + __u32 edx; + __u32 padding; +}; + +/* for KVM_SET_CPUID */ +struct kvm_cpuid { + __u32 nent; + __u32 padding; + struct kvm_cpuid_entry entries[0]; +}; + +4.20 KVM_SET_SIGNAL_MASK + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_signal_mask (in) +Returns: 0 on success, -1 on error + +Defines which signals are blocked during execution of KVM_RUN. This +signal mask temporarily overrides the threads signal mask. Any +unblocked signal received (except SIGKILL and SIGSTOP, which retain +their traditional behaviour) will cause KVM_RUN to return with -EINTR. + +Note the signal will only be delivered if not blocked by the original +signal mask. + +/* for KVM_SET_SIGNAL_MASK */ +struct kvm_signal_mask { + __u32 len; + __u8 sigset[0]; +}; + +4.21 KVM_GET_FPU + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_fpu (out) +Returns: 0 on success, -1 on error + +Reads the floating point state from the vcpu. + +/* for KVM_GET_FPU and KVM_SET_FPU */ +struct kvm_fpu { + __u8 fpr[8][16]; + __u16 fcw; + __u16 fsw; + __u8 ftwx; /* in fxsave format */ + __u8 pad1; + __u16 last_opcode; + __u64 last_ip; + __u64 last_dp; + __u8 xmm[16][16]; + __u32 mxcsr; + __u32 pad2; +}; + +4.22 KVM_SET_FPU + +Capability: basic +Architectures: x86 +Type: vcpu ioctl +Parameters: struct kvm_fpu (in) +Returns: 0 on success, -1 on error + +Writes the floating point state to the vcpu. + +/* for KVM_GET_FPU and KVM_SET_FPU */ +struct kvm_fpu { + __u8 fpr[8][16]; + __u16 fcw; + __u16 fsw; + __u8 ftwx; /* in fxsave format */ + __u8 pad1; + __u16 last_opcode; + __u64 last_ip; + __u64 last_dp; + __u8 xmm[16][16]; + __u32 mxcsr; + __u32 pad2; +}; + +5. The kvm_run structure + +Application code obtains a pointer to the kvm_run structure by +mmap()ing a vcpu fd. From that point, application code can control +execution by changing fields in kvm_run prior to calling the KVM_RUN +ioctl, and obtain information about the reason KVM_RUN returned by +looking up structure members. + +struct kvm_run { + /* in */ + __u8 request_interrupt_window; + +Request that KVM_RUN return when it becomes possible to inject external +interrupts into the guest. Useful in conjunction with KVM_INTERRUPT. + + __u8 padding1[7]; + + /* out */ + __u32 exit_reason; + +When KVM_RUN has returned successfully (return value 0), this informs +application code why KVM_RUN has returned. Allowable values for this +field are detailed below. + + __u8 ready_for_interrupt_injection; + +If request_interrupt_window has been specified, this field indicates +an interrupt can be injected now with KVM_INTERRUPT. + + __u8 if_flag; + +The value of the current interrupt flag. Only valid if in-kernel +local APIC is not used. + + __u8 padding2[2]; + + /* in (pre_kvm_run), out (post_kvm_run) */ + __u64 cr8; + +The value of the cr8 register. Only valid if in-kernel local APIC is +not used. Both input and output. + + __u64 apic_base; + +The value of the APIC BASE msr. Only valid if in-kernel local +APIC is not used. Both input and output. + + union { + /* KVM_EXIT_UNKNOWN */ + struct { + __u64 hardware_exit_reason; + } hw; + +If exit_reason is KVM_EXIT_UNKNOWN, the vcpu has exited due to unknown +reasons. Further architecture-specific information is available in +hardware_exit_reason. + + /* KVM_EXIT_FAIL_ENTRY */ + struct { + __u64 hardware_entry_failure_reason; + } fail_entry; + +If exit_reason is KVM_EXIT_FAIL_ENTRY, the vcpu could not be run due +to unknown reasons. Further architecture-specific information is +available in hardware_entry_failure_reason. + + /* KVM_EXIT_EXCEPTION */ + struct { + __u32 exception; + __u32 error_code; + } ex; + +Unused. + + /* KVM_EXIT_IO */ + struct { +#define KVM_EXIT_IO_IN 0 +#define KVM_EXIT_IO_OUT 1 + __u8 direction; + __u8 size; /* bytes */ + __u16 port; + __u32 count; + __u64 data_offset; /* relative to kvm_run start */ + } io; + +If exit_reason is KVM_EXIT_IO_IN or KVM_EXIT_IO_OUT, then the vcpu has +executed a port I/O instruction which could not be satisfied by kvm. +data_offset describes where the data is located (KVM_EXIT_IO_OUT) or +where kvm expects application code to place the data for the next +KVM_RUN invocation (KVM_EXIT_IO_IN). Data format is a patcked array. + + struct { + struct kvm_debug_exit_arch arch; + } debug; + +Unused. + + /* KVM_EXIT_MMIO */ + struct { + __u64 phys_addr; + __u8 data[8]; + __u32 len; + __u8 is_write; + } mmio; + +If exit_reason is KVM_EXIT_MMIO or KVM_EXIT_IO_OUT, then the vcpu has +executed a memory-mapped I/O instruction which could not be satisfied +by kvm. The 'data' member contains the written data if 'is_write' is +true, and should be filled by application code otherwise. + + /* KVM_EXIT_HYPERCALL */ + struct { + __u64 nr; + __u64 args[6]; + __u64 ret; + __u32 longmode; + __u32 pad; + } hypercall; + +Unused. + + /* KVM_EXIT_TPR_ACCESS */ + struct { + __u64 rip; + __u32 is_write; + __u32 pad; + } tpr_access; + +To be documented (KVM_TPR_ACCESS_REPORTING). + + /* KVM_EXIT_S390_SIEIC */ + struct { + __u8 icptcode; + __u64 mask; /* psw upper half */ + __u64 addr; /* psw lower half */ + __u16 ipa; + __u32 ipb; + } s390_sieic; + +s390 specific. + + /* KVM_EXIT_S390_RESET */ +#define KVM_S390_RESET_POR 1 +#define KVM_S390_RESET_CLEAR 2 +#define KVM_S390_RESET_SUBSYSTEM 4 +#define KVM_S390_RESET_CPU_INIT 8 +#define KVM_S390_RESET_IPL 16 + __u64 s390_reset_flags; + +s390 specific. + + /* KVM_EXIT_DCR */ + struct { + __u32 dcrn; + __u32 data; + __u8 is_write; + } dcr; + +powerpc specific. + + /* Fix the size of the union. */ + char padding[256]; + }; +}; -- cgit v1.2.3-70-g09d2 From fef07aae9cd9ed82f94228c311b35360f1f38902 Mon Sep 17 00:00:00 2001 From: Andre Przywara Date: Fri, 10 Jul 2009 14:20:35 +0200 Subject: KVM: add module parameters documentation Signed-off-by: Andre Przywara Signed-off-by: Avi Kivity --- Documentation/kernel-parameters.txt | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 7936b801fe6..877a02a12e0 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -57,6 +57,7 @@ parameter is applicable: ISAPNP ISA PnP code is enabled. ISDN Appropriate ISDN support is enabled. JOY Appropriate joystick support is enabled. + KVM Kernel Virtual Machine support is enabled. LIBATA Libata driver is enabled LP Printer support is enabled. LOOP Loopback device support is enabled. @@ -1098,6 +1099,44 @@ and is between 256 and 4096 characters. It is defined in the file kstack=N [X86] Print N words from the kernel stack in oops dumps. + kvm.ignore_msrs=[KVM] Ignore guest accesses to unhandled MSRs. + Default is 0 (don't ignore, but inject #GP) + + kvm.oos_shadow= [KVM] Disable out-of-sync shadow paging. + Default is 1 (enabled) + + kvm-amd.nested= [KVM,AMD] Allow nested virtualization in KVM/SVM. + Default is 0 (off) + + kvm-amd.npt= [KVM,AMD] Disable nested paging (virtualized MMU) + for all guests. + Default is 1 (enabled) if in 64bit or 32bit-PAE mode + + kvm-intel.bypass_guest_pf= + [KVM,Intel] Disables bypassing of guest page faults + on Intel chips. Default is 1 (enabled) + + kvm-intel.ept= [KVM,Intel] Disable extended page tables + (virtualized MMU) support on capable Intel chips. + Default is 1 (enabled) + + kvm-intel.emulate_invalid_guest_state= + [KVM,Intel] Enable emulation of invalid guest states + Default is 0 (disabled) + + kvm-intel.flexpriority= + [KVM,Intel] Disable FlexPriority feature (TPR shadow). + Default is 1 (enabled) + + kvm-intel.unrestricted_guest= + [KVM,Intel] Disable unrestricted guest feature + (virtualized real and unpaged mode) on capable + Intel chips. Default is 1 (enabled) + + kvm-intel.vpid= [KVM,Intel] Disable Virtual Processor Identification + feature (tagged TLBs) on capable Intel chips. + Default is 1 (enabled) + l2cr= [PPC] l3cr= [PPC] -- cgit v1.2.3-70-g09d2 From 0aaeb3b1087b21fef434f1bae6e6495c12ee2f55 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Thu, 13 Aug 2009 20:05:48 +0530 Subject: Documentation: Update KVM list email address The KVM list moved to vger.kernel.org last year Signed-off-by: Amit Shah Signed-off-by: Avi Kivity --- Documentation/ioctl/ioctl-number.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index dbea4f95fc8..999a2017df7 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -192,7 +192,7 @@ Code Seq# Include File Comments 0xAD 00 Netfilter device in development: 0xAE all linux/kvm.h Kernel-based Virtual Machine - + 0xB0 all RATIO devices in development: 0xB1 00-1F PPPoX -- cgit v1.2.3-70-g09d2 From 5dadbfd64724c41716d4fc82df6f01b023d5b15d Mon Sep 17 00:00:00 2001 From: Avi Kivity Date: Sun, 23 Aug 2009 17:08:04 +0300 Subject: KVM: Document KVM_CAP_IRQCHIP Signed-off-by: Avi Kivity --- Documentation/kvm/api.txt | 76 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) (limited to 'Documentation') diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt index 1b1c22da211..5a4bc8cf6d0 100644 --- a/Documentation/kvm/api.txt +++ b/Documentation/kvm/api.txt @@ -517,6 +517,82 @@ struct kvm_fpu { __u32 pad2; }; +4.23 KVM_CREATE_IRQCHIP + +Capability: KVM_CAP_IRQCHIP +Architectures: x86, ia64 +Type: vm ioctl +Parameters: none +Returns: 0 on success, -1 on error + +Creates an interrupt controller model in the kernel. On x86, creates a virtual +ioapic, a virtual PIC (two PICs, nested), and sets up future vcpus to have a +local APIC. IRQ routing for GSIs 0-15 is set to both PIC and IOAPIC; GSI 16-23 +only go to the IOAPIC. On ia64, a IOSAPIC is created. + +4.24 KVM_IRQ_LINE + +Capability: KVM_CAP_IRQCHIP +Architectures: x86, ia64 +Type: vm ioctl +Parameters: struct kvm_irq_level +Returns: 0 on success, -1 on error + +Sets the level of a GSI input to the interrupt controller model in the kernel. +Requires that an interrupt controller model has been previously created with +KVM_CREATE_IRQCHIP. Note that edge-triggered interrupts require the level +to be set to 1 and then back to 0. + +struct kvm_irq_level { + union { + __u32 irq; /* GSI */ + __s32 status; /* not used for KVM_IRQ_LEVEL */ + }; + __u32 level; /* 0 or 1 */ +}; + +4.25 KVM_GET_IRQCHIP + +Capability: KVM_CAP_IRQCHIP +Architectures: x86, ia64 +Type: vm ioctl +Parameters: struct kvm_irqchip (in/out) +Returns: 0 on success, -1 on error + +Reads the state of a kernel interrupt controller created with +KVM_CREATE_IRQCHIP into a buffer provided by the caller. + +struct kvm_irqchip { + __u32 chip_id; /* 0 = PIC1, 1 = PIC2, 2 = IOAPIC */ + __u32 pad; + union { + char dummy[512]; /* reserving space */ + struct kvm_pic_state pic; + struct kvm_ioapic_state ioapic; + } chip; +}; + +4.26 KVM_SET_IRQCHIP + +Capability: KVM_CAP_IRQCHIP +Architectures: x86, ia64 +Type: vm ioctl +Parameters: struct kvm_irqchip (in) +Returns: 0 on success, -1 on error + +Sets the state of a kernel interrupt controller created with +KVM_CREATE_IRQCHIP from a buffer provided by the caller. + +struct kvm_irqchip { + __u32 chip_id; /* 0 = PIC1, 1 = PIC2, 2 = IOAPIC */ + __u32 pad; + union { + char dummy[512]; /* reserving space */ + struct kvm_pic_state pic; + struct kvm_ioapic_state ioapic; + } chip; +}; + 5. The kvm_run structure Application code obtains a pointer to the kvm_run structure by -- cgit v1.2.3-70-g09d2 From e8188807b7cd14e0a001946005f0c58f9dd9dfe6 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 26 May 2009 15:18:52 +0200 Subject: Doc: seq_file.txt fix wrong dd command example. Small error in the "dd" command example, "out=" should be "of=". Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Jonathan Corbet --- Documentation/filesystems/seq_file.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/filesystems/seq_file.txt b/Documentation/filesystems/seq_file.txt index b843743aa0b..0d15ebccf5b 100644 --- a/Documentation/filesystems/seq_file.txt +++ b/Documentation/filesystems/seq_file.txt @@ -46,7 +46,7 @@ better to do. The file is seekable, in that one can do something like the following: dd if=/proc/sequence of=out1 count=1 - dd if=/proc/sequence skip=1 out=out2 count=1 + dd if=/proc/sequence skip=1 of=out2 count=1 Then concatenate the output files out1 and out2 and get the right result. Yes, it is a thoroughly useless module, but the point is to show -- cgit v1.2.3-70-g09d2 From 6c19efb46aacf2c5043ad210b888ee58ffb848c0 Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 8 Sep 2009 17:49:37 -0600 Subject: Document the flex_array library. A brief document on how to use flexible arrays, derived from an article first published on LWN. Signed-off-by: Jonathan Corbet --- Documentation/flexible-arrays.txt | 99 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 Documentation/flexible-arrays.txt (limited to 'Documentation') diff --git a/Documentation/flexible-arrays.txt b/Documentation/flexible-arrays.txt new file mode 100644 index 00000000000..84eb26808de --- /dev/null +++ b/Documentation/flexible-arrays.txt @@ -0,0 +1,99 @@ +Using flexible arrays in the kernel +Last updated for 2.6.31 +Jonathan Corbet + +Large contiguous memory allocations can be unreliable in the Linux kernel. +Kernel programmers will sometimes respond to this problem by allocating +pages with vmalloc(). This solution not ideal, though. On 32-bit systems, +memory from vmalloc() must be mapped into a relatively small address space; +it's easy to run out. On SMP systems, the page table changes required by +vmalloc() allocations can require expensive cross-processor interrupts on +all CPUs. And, on all systems, use of space in the vmalloc() range +increases pressure on the translation lookaside buffer (TLB), reducing the +performance of the system. + +In many cases, the need for memory from vmalloc() can be eliminated by +piecing together an array from smaller parts; the flexible array library +exists to make this task easier. + +A flexible array holds an arbitrary (within limits) number of fixed-sized +objects, accessed via an integer index. Sparse arrays are handled +reasonably well. Only single-page allocations are made, so memory +allocation failures should be relatively rare. The down sides are that the +arrays cannot be indexed directly, individual object size cannot exceed the +system page size, and putting data into a flexible array requires a copy +operation. It's also worth noting that flexible arrays do no internal +locking at all; if concurrent access to an array is possible, then the +caller must arrange for appropriate mutual exclusion. + +The creation of a flexible array is done with: + + #include + + struct flex_array *flex_array_alloc(int element_size, + unsigned int total, + gfp_t flags); + +The individual object size is provided by element_size, while total is the +maximum number of objects which can be stored in the array. The flags +argument is passed directly to the internal memory allocation calls. With +the current code, using flags to ask for high memory is likely to lead to +notably unpleasant side effects. + +Storing data into a flexible array is accomplished with a call to: + + int flex_array_put(struct flex_array *array, unsigned int element_nr, + void *src, gfp_t flags); + +This call will copy the data from src into the array, in the position +indicated by element_nr (which must be less than the maximum specified when +the array was created). If any memory allocations must be performed, flags +will be used. The return value is zero on success, a negative error code +otherwise. + +There might possibly be a need to store data into a flexible array while +running in some sort of atomic context; in this situation, sleeping in the +memory allocator would be a bad thing. That can be avoided by using +GFP_ATOMIC for the flags value, but, often, there is a better way. The +trick is to ensure that any needed memory allocations are done before +entering atomic context, using: + + int flex_array_prealloc(struct flex_array *array, unsigned int start, + unsigned int end, gfp_t flags); + +This function will ensure that memory for the elements indexed in the range +defined by start and end has been allocated. Thereafter, a +flex_array_put() call on an element in that range is guaranteed not to +block. + +Getting data back out of the array is done with: + + void *flex_array_get(struct flex_array *fa, unsigned int element_nr); + +The return value is a pointer to the data element, or NULL if that +particular element has never been allocated. + +Note that it is possible to get back a valid pointer for an element which +has never been stored in the array. Memory for array elements is allocated +one page at a time; a single allocation could provide memory for several +adjacent elements. The flexible array code does not know if a specific +element has been written; it only knows if the associated memory is +present. So a flex_array_get() call on an element which was never stored +in the array has the potential to return a pointer to random data. If the +caller does not have a separate way to know which elements were actually +stored, it might be wise, at least, to add GFP_ZERO to the flags argument +to ensure that all elements are zeroed. + +There is no way to remove a single element from the array. It is possible, +though, to remove all elements with a call to: + + void flex_array_free_parts(struct flex_array *array); + +This call frees all elements, but leaves the array itself in place. +Freeing the entire array is done with: + + void flex_array_free(struct flex_array *array); + +As of this writing, there are no users of flexible arrays in the mainline +kernel. The functions described here are also not exported to modules; +that will probably be fixed when somebody comes up with a need for it. -- cgit v1.2.3-70-g09d2 From c114728af2acdca0bd8b1d2f5792e393c775f5fc Mon Sep 17 00:00:00 2001 From: Hans-Joachim Picht Date: Fri, 11 Sep 2009 10:28:47 +0200 Subject: [S390] add call home support Signed-off-by: Hans-Joachim Picht Signed-off-by: Martin Schwidefsky --- Documentation/sysctl/kernel.txt | 16 +++ drivers/s390/char/Kconfig | 10 ++ drivers/s390/char/Makefile | 1 + drivers/s390/char/sclp.h | 4 +- drivers/s390/char/sclp_async.c | 224 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 drivers/s390/char/sclp_async.c (limited to 'Documentation') diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 322a00bb99d..2dbff53369d 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -19,6 +19,7 @@ Currently, these files might (depending on your configuration) show up in /proc/sys/kernel: - acpi_video_flags - acct +- callhome [ S390 only ] - auto_msgmni - core_pattern - core_uses_pid @@ -91,6 +92,21 @@ valid for 30 seconds. ============================================================== +callhome: + +Controls the kernel's callhome behavior in case of a kernel panic. + +The s390 hardware allows an operating system to send a notification +to a service organization (callhome) in case of an operating system panic. + +When the value in this file is 0 (which is the default behavior) +nothing happens in case of a kernel panic. If this value is set to "1" +the complete kernel oops message is send to the IBM customer service +organization in case the mainframe the Linux operating system is running +on has a service contract with IBM. + +============================================================== + core_pattern: core_pattern is used to specify a core dumpfile pattern name. diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index 0769ced52db..4e34d3686c2 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig @@ -82,6 +82,16 @@ config SCLP_CPI You should only select this option if you know what you are doing, need this feature and intend to run your kernel in LPAR. +config SCLP_ASYNC + tristate "Support for Call Home via Asynchronous SCLP Records" + depends on S390 + help + This option enables the call home function, which is able to inform + the service element and connected organisations about a kernel panic. + You should only select this option if you know what you are doing, + want for inform other people about your kernel panics, + need this feature and intend to run your kernel in LPAR. + config S390_TAPE tristate "S/390 tape device support" depends on CCW diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index 7e73e39a174..efb500ab66c 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_SCLP_TTY) += sclp_tty.o obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o +obj-$(CONFIG_SCLP_ASYNC) += sclp_async.o obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 60e7cb07095..6bb5a6bdfab 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -27,6 +27,7 @@ #define EVTYP_VT220MSG 0x1A #define EVTYP_CONFMGMDATA 0x04 #define EVTYP_SDIAS 0x1C +#define EVTYP_ASYNC 0x0A #define EVTYP_OPCMD_MASK 0x80000000 #define EVTYP_MSG_MASK 0x40000000 @@ -38,6 +39,7 @@ #define EVTYP_VT220MSG_MASK 0x00000040 #define EVTYP_CONFMGMDATA_MASK 0x10000000 #define EVTYP_SDIAS_MASK 0x00000010 +#define EVTYP_ASYNC_MASK 0x00400000 #define GNRLMSGFLGS_DOM 0x8000 #define GNRLMSGFLGS_SNDALRM 0x4000 @@ -85,12 +87,12 @@ struct sccb_header { } __attribute__((packed)); extern u64 sclp_facilities; - #define SCLP_HAS_CHP_INFO (sclp_facilities & 0x8000000000000000ULL) #define SCLP_HAS_CHP_RECONFIG (sclp_facilities & 0x2000000000000000ULL) #define SCLP_HAS_CPU_INFO (sclp_facilities & 0x0800000000000000ULL) #define SCLP_HAS_CPU_RECONFIG (sclp_facilities & 0x0400000000000000ULL) + struct gds_subvector { u8 length; u8 key; diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c new file mode 100644 index 00000000000..daaec185ed3 --- /dev/null +++ b/drivers/s390/char/sclp_async.c @@ -0,0 +1,224 @@ +/* + * Enable Asynchronous Notification via SCLP. + * + * Copyright IBM Corp. 2009 + * Author(s): Hans-Joachim Picht + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sclp.h" + +static int callhome_enabled; +static struct sclp_req *request; +static struct sclp_async_sccb *sccb; +static int sclp_async_send_wait(char *message); +static struct ctl_table_header *callhome_sysctl_header; +static DEFINE_SPINLOCK(sclp_async_lock); +static char nodename[64]; +#define SCLP_NORMAL_WRITE 0x00 + +struct async_evbuf { + struct evbuf_header header; + u64 reserved; + u8 rflags; + u8 empty; + u8 rtype; + u8 otype; + char comp_id[12]; + char data[3000]; /* there is still some space left */ +} __attribute__((packed)); + +struct sclp_async_sccb { + struct sccb_header header; + struct async_evbuf evbuf; +} __attribute__((packed)); + +static struct sclp_register sclp_async_register = { + .send_mask = EVTYP_ASYNC_MASK, +}; + +static int call_home_on_panic(struct notifier_block *self, + unsigned long event, void *data) +{ + strncat(data, nodename, strlen(nodename)); + sclp_async_send_wait(data); + return NOTIFY_DONE; +} + +static struct notifier_block call_home_panic_nb = { + .notifier_call = call_home_on_panic, + .priority = INT_MAX, +}; + +static int proc_handler_callhome(ctl_table *ctl, int write, struct file *filp, + void __user *buffer, size_t *count, + loff_t *ppos) +{ + unsigned long val; + int len, rc; + char buf[2]; + + if (!*count | (*ppos && !write)) { + *count = 0; + return 0; + } + if (!write) { + len = sprintf(buf, "%d\n", callhome_enabled); + buf[len] = '\0'; + rc = copy_to_user(buffer, buf, sizeof(buf)); + if (rc != 0) + return -EFAULT; + } else { + len = *count; + rc = copy_from_user(buf, buffer, sizeof(buf)); + if (rc != 0) + return -EFAULT; + if (strict_strtoul(buf, 0, &val) != 0) + return -EINVAL; + if (val != 0 && val != 1) + return -EINVAL; + callhome_enabled = val; + } + *count = len; + *ppos += len; + return 0; +} + +static struct ctl_table callhome_table[] = { + { + .procname = "callhome", + .mode = 0644, + .proc_handler = &proc_handler_callhome, + }, + { .ctl_name = 0 } +}; + +static struct ctl_table kern_dir_table[] = { + { + .ctl_name = CTL_KERN, + .procname = "kernel", + .maxlen = 0, + .mode = 0555, + .child = callhome_table, + }, + { .ctl_name = 0 } +}; + +/* + * Function used to transfer asynchronous notification + * records which waits for send completion + */ +static int sclp_async_send_wait(char *message) +{ + struct async_evbuf *evb; + int rc; + unsigned long flags; + + if (!callhome_enabled) + return 0; + sccb->evbuf.header.type = EVTYP_ASYNC; + sccb->evbuf.rtype = 0xA5; + sccb->evbuf.otype = 0x00; + evb = &sccb->evbuf; + request->command = SCLP_CMDW_WRITE_EVENT_DATA; + request->sccb = sccb; + request->status = SCLP_REQ_FILLED; + strncpy(sccb->evbuf.data, message, sizeof(sccb->evbuf.data)); + /* + * Retain Queue + * e.g. 5639CC140 500 Red Hat RHEL5 Linux for zSeries (RHEL AS) + */ + strncpy(sccb->evbuf.comp_id, "000000000", sizeof(sccb->evbuf.comp_id)); + sccb->evbuf.header.length = sizeof(sccb->evbuf); + sccb->header.length = sizeof(sccb->evbuf) + sizeof(sccb->header); + sccb->header.function_code = SCLP_NORMAL_WRITE; + rc = sclp_add_request(request); + if (rc) + return rc; + spin_lock_irqsave(&sclp_async_lock, flags); + while (request->status != SCLP_REQ_DONE && + request->status != SCLP_REQ_FAILED) { + sclp_sync_wait(); + } + spin_unlock_irqrestore(&sclp_async_lock, flags); + if (request->status != SCLP_REQ_DONE) + return -EIO; + rc = ((struct sclp_async_sccb *) + request->sccb)->header.response_code; + if (rc != 0x0020) + return -EIO; + if (evb->header.flags != 0x80) + return -EIO; + return rc; +} + +static int __init sclp_async_init(void) +{ + int rc; + + rc = sclp_register(&sclp_async_register); + if (rc) + return rc; + callhome_sysctl_header = register_sysctl_table(kern_dir_table); + if (!callhome_sysctl_header) { + rc = -ENOMEM; + goto out_sclp; + } + if (!(sclp_async_register.sclp_receive_mask & EVTYP_ASYNC_MASK)) { + rc = -EOPNOTSUPP; + goto out_sclp; + } + rc = -ENOMEM; + request = kzalloc(sizeof(struct sclp_req), GFP_KERNEL); + if (!request) + goto out_sys; + sccb = (struct sclp_async_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); + if (!sccb) + goto out_mem; + rc = atomic_notifier_chain_register(&panic_notifier_list, + &call_home_panic_nb); + if (rc) + goto out_mem; + + strncpy(nodename, init_utsname()->nodename, 64); + return 0; + +out_mem: + kfree(request); + free_page((unsigned long) sccb); +out_sys: + unregister_sysctl_table(callhome_sysctl_header); +out_sclp: + sclp_unregister(&sclp_async_register); + return rc; + +} +module_init(sclp_async_init); + +static void __exit sclp_async_exit(void) +{ + atomic_notifier_chain_unregister(&panic_notifier_list, + &call_home_panic_nb); + unregister_sysctl_table(callhome_sysctl_header); + sclp_unregister(&sclp_async_register); + free_page((unsigned long) sccb); + kfree(request); +} +module_exit(sclp_async_exit); + +MODULE_AUTHOR("Copyright IBM Corp. 2009"); +MODULE_AUTHOR("Hans-Joachim Picht "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SCLP Asynchronous Notification Records"); -- cgit v1.2.3-70-g09d2 From f64d04c042193183c6dad98944ae2861b998e8b7 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Fri, 11 Sep 2009 10:28:59 +0200 Subject: [S390] s390dbf: Add description for usage of "%s" in sprintf events Using "%s" in sprintf event functions is dangerous. This patch adds a short description for this issue to the s390 debug feature documentation. Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- Documentation/s390/s390dbf.txt | 7 +++++++ arch/s390/include/asm/debug.h | 9 ++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/s390/s390dbf.txt b/Documentation/s390/s390dbf.txt index 2d10053dd97..ae66f9b90a2 100644 --- a/Documentation/s390/s390dbf.txt +++ b/Documentation/s390/s390dbf.txt @@ -495,6 +495,13 @@ and for each vararg a long value. So e.g. for a debug entry with a format string plus two varargs one would need to allocate a (3 * sizeof(long)) byte data area in the debug_register() function. +IMPORTANT: Using "%s" in sprintf event functions is dangerous. You can only +use "%s" in the sprintf event functions, if the memory for the passed string is +available as long as the debug feature exists. The reason behind this is that +due to performance considerations only a pointer to the string is stored in +the debug feature. If you log a string that is freed afterwards, you will get +an OOPS when inspecting the debug feature, because then the debug feature will +access the already freed memory. NOTE: If using the sprintf view do NOT use other event/exception functions than the sprintf-event and -exception functions. diff --git a/arch/s390/include/asm/debug.h b/arch/s390/include/asm/debug.h index 31ed5686a96..18124b75a7a 100644 --- a/arch/s390/include/asm/debug.h +++ b/arch/s390/include/asm/debug.h @@ -167,6 +167,10 @@ debug_text_event(debug_info_t* id, int level, const char* txt) return debug_event_common(id,level,txt,strlen(txt)); } +/* + * IMPORTANT: Use "%s" in sprintf format strings with care! Only pointers are + * stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details! + */ extern debug_entry_t * debug_sprintf_event(debug_info_t* id,int level,char *string,...) __attribute__ ((format(printf, 3, 4))); @@ -206,7 +210,10 @@ debug_text_exception(debug_info_t* id, int level, const char* txt) return debug_exception_common(id,level,txt,strlen(txt)); } - +/* + * IMPORTANT: Use "%s" in sprintf format strings with care! Only pointers are + * stored in the s390dbf. See Documentation/s390/s390dbf.txt for more details! + */ extern debug_entry_t * debug_sprintf_exception(debug_info_t* id,int level,char *string,...) __attribute__ ((format(printf, 3, 4))); -- cgit v1.2.3-70-g09d2 From 7c8b56795fdf59761ee3475b6add2fd4b635d2b6 Mon Sep 17 00:00:00 2001 From: Zhenyu Wang Date: Sun, 5 Jul 2009 10:51:21 -0300 Subject: V4L/DVB (12190): em28xx: Add support for Gadmei UTV330+ em28xx: Add support for Gadmei UTV330+ Signed-off-by: Zhenyu Wang Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.em28xx | 2 +- drivers/media/video/em28xx/em28xx-cards.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index e352d754875..66e5f829577 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -33,7 +33,7 @@ 34 -> Terratec Cinergy A Hybrid XS (em2860) [0ccd:004f] 35 -> Typhoon DVD Maker (em2860) 36 -> NetGMBH Cam (em2860) - 37 -> Gadmei UTV330 (em2860) + 37 -> Gadmei UTV330 (em2860) [eb1a:50a6] 38 -> Yakumo MovieMixer (em2861) 39 -> KWorld PVRTV 300U (em2861) [eb1a:e300] 40 -> Plextor ConvertX PX-TV100U (em2861) [093b:a005] diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 1c2e544eda7..22a464f5007 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -1649,6 +1649,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U }, { USB_DEVICE(0x04bb, 0x0515), .driver_info = EM2820_BOARD_IODATA_GVMVP_SZ }, + { USB_DEVICE(0xeb1a, 0x50a6), + .driver_info = EM2860_BOARD_GADMEI_UTV330 }, { }, }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); -- cgit v1.2.3-70-g09d2 From 3eed78259935bc833242f6d47e7b77cd327334c7 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 20 Jun 2009 04:58:57 -0300 Subject: V4L/DVB (12227): gspca - pac7311: Webcam 093a:2629 added. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/gspca.txt | 1 + drivers/media/video/gspca/pac7311.c | 1 + 2 files changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 573f95b5880..8978386d36f 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -235,6 +235,7 @@ pac7311 093a:2621 PAC731x pac7311 093a:2622 Genius Eye 312 pac7311 093a:2624 PAC7302 pac7311 093a:2626 Labtec 2200 +pac7311 093a:2629 Genious iSlim 300 pac7311 093a:262a Webcam 300k pac7311 093a:262c Philips SPC 230 NC zc3xx 0ac8:0302 Z-star Vimicro zc0302 diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index e1e3a3a5048..0caf3c07573 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -1068,6 +1068,7 @@ static __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2622), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302}, + {USB_DEVICE(0x093a, 0x2629), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x262c), .driver_info = SENSOR_PAC7302}, {} -- cgit v1.2.3-70-g09d2 From 1852e75a55287156f2a435ca4ea4f8c1c75bac6c Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Sat, 27 Jun 2009 05:33:48 -0300 Subject: V4L/DVB (12228): gspca - vc032x: Webcam 0ac8:c301 added. Only the back sensor (mi1320_soc) is usable. Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/gspca.txt | 1 + drivers/media/video/gspca/vc032x.c | 46 ++++++++++++++++++++++++++----------- 2 files changed, 34 insertions(+), 13 deletions(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 8978386d36f..7045ebf1d72 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -248,6 +248,7 @@ zc3xx 0ac8:305b Z-star Vimicro zc0305b zc3xx 0ac8:307b Ldlc VC302+Ov7620 vc032x 0ac8:c001 Sony embedded vimicro vc032x 0ac8:c002 Sony embedded vimicro +vc032x 0ac8:c301 Samsung Q1 Ultra Premium spca508 0af9:0010 Hama USB Sightcam 100 spca508 0af9:0011 Hama USB Sightcam 100 sonixb 0c45:6001 Genius VideoCAM NB diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c index 26dd155efcc..5b6f717d3fe 100644 --- a/drivers/media/video/gspca/vc032x.c +++ b/drivers/media/video/gspca/vc032x.c @@ -52,6 +52,7 @@ struct sd { #define SENSOR_OV7670 6 #define SENSOR_PO1200 7 #define SENSOR_PO3130NC 8 + u8 ninput; /* != 0 when 2 sensors - SamsungQ1 */ }; /* V4L2 controls supported by the driver */ @@ -2342,11 +2343,18 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev, static int vc032x_probe_sensor(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; int i; u16 value; const struct sensor_info *ptsensor_info; +/*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/ + if (sd->ninput != 0) { + reg_w(dev, 0xa0, 0x01, 0xb301); + reg_w(dev, 0x89, 0xf0ff, 0xffff); /* select the back sensor */ + } + reg_r(gspca_dev, 0xa1, 0xbfcf, 1); PDEBUG(D_PROBE, "check sensor header %02x", gspca_dev->usb_buf[0]); for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) { @@ -2466,7 +2474,8 @@ static int sd_config(struct gspca_dev *gspca_dev, }; cam = &gspca_dev->cam; - sd->bridge = id->driver_info; + sd->bridge = id->driver_info >> 8; + sd->ninput = id->driver_info & 0xff; sensor = vc032x_probe_sensor(gspca_dev); switch (sensor) { case -1: @@ -2635,6 +2644,13 @@ static int sd_start(struct gspca_dev *gspca_dev) mi1320_soc_InitQVGA, }; +/*fixme: back sensor only*/ + if (sd->ninput != 0) { + reg_w(gspca_dev->dev, 0x89, 0xf0ff, 0xffff); + reg_w(gspca_dev->dev, 0xa9, 0x8348, 0x000e); + reg_w(gspca_dev->dev, 0xa9, 0x0000, 0x001a); + } + /* Assume start use the good resolution from gspca_dev->mode */ if (sd->bridge == BRIDGE_VC0321) { reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec); @@ -2906,19 +2922,23 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ +#define BF(bridge, flags) \ + .driver_info = (BRIDGE_ ## bridge << 8) \ + | (flags) static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x405b), .driver_info = BRIDGE_VC0323}, - {USB_DEVICE(0x046d, 0x0892), .driver_info = BRIDGE_VC0321}, - {USB_DEVICE(0x046d, 0x0896), .driver_info = BRIDGE_VC0321}, - {USB_DEVICE(0x046d, 0x0897), .driver_info = BRIDGE_VC0321}, - {USB_DEVICE(0x0ac8, 0x0321), .driver_info = BRIDGE_VC0321}, - {USB_DEVICE(0x0ac8, 0x0323), .driver_info = BRIDGE_VC0323}, - {USB_DEVICE(0x0ac8, 0x0328), .driver_info = BRIDGE_VC0321}, - {USB_DEVICE(0x0ac8, 0xc001), .driver_info = BRIDGE_VC0321}, - {USB_DEVICE(0x0ac8, 0xc002), .driver_info = BRIDGE_VC0321}, - {USB_DEVICE(0x15b8, 0x6001), .driver_info = BRIDGE_VC0323}, - {USB_DEVICE(0x15b8, 0x6002), .driver_info = BRIDGE_VC0323}, - {USB_DEVICE(0x17ef, 0x4802), .driver_info = BRIDGE_VC0323}, + {USB_DEVICE(0x041e, 0x405b), BF(VC0323, 0)}, + {USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)}, + {USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)}, + {USB_DEVICE(0x046d, 0x0897), BF(VC0321, 0)}, + {USB_DEVICE(0x0ac8, 0x0321), BF(VC0321, 0)}, + {USB_DEVICE(0x0ac8, 0x0323), BF(VC0323, 0)}, + {USB_DEVICE(0x0ac8, 0x0328), BF(VC0321, 0)}, + {USB_DEVICE(0x0ac8, 0xc001), BF(VC0321, 0)}, + {USB_DEVICE(0x0ac8, 0xc002), BF(VC0321, 0)}, + {USB_DEVICE(0x0ac8, 0xc301), BF(VC0323, 1)}, + {USB_DEVICE(0x15b8, 0x6001), BF(VC0323, 0)}, + {USB_DEVICE(0x15b8, 0x6002), BF(VC0323, 0)}, + {USB_DEVICE(0x17ef, 0x4802), BF(VC0323, 0)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); -- cgit v1.2.3-70-g09d2 From 2365b2d307ee0323062c674ea0495584085e8c24 Mon Sep 17 00:00:00 2001 From: David Wong Date: Wed, 17 Jun 2009 01:38:12 -0300 Subject: V4L/DVB (12272): cx23885: add card Magic-Pro ProHDTV Extreme 2 cx23885: add card Magic-Pro ProHDTV Extreme 2 PCI-E. Signed-off-by: David T.L. Wong Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx23885 | 1 + drivers/media/video/cx23885/cx23885-cards.c | 12 ++++++++++- drivers/media/video/cx23885/cx23885-dvb.c | 33 +++++++++++++++++++++++++++++ drivers/media/video/cx23885/cx23885.h | 1 + 4 files changed, 46 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 index 450b8f8c389..19feb514f93 100644 --- a/Documentation/video4linux/CARDLIST.cx23885 +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -21,3 +21,4 @@ 20 -> Hauppauge WinTV-HVR1255 [0070:2251] 21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295] 22 -> Mygica X8506 DMB-TH [14f1:8651] + 23 -> Magic-Pro ProHDTV Extreme 2 [14f1:8657] diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index ce29b5e34a1..a9d36298147 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -201,6 +201,10 @@ struct cx23885_board cx23885_boards[] = { .name = "Mygica X8506 DMB-TH", .portb = CX23885_MPEG_DVB, }, + [CX23885_BOARD_MAGICPRO_PROHDTVE2] = { + .name = "Magic-Pro ProHDTV Extreme 2", + .portb = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -324,6 +328,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x14f1, .subdevice = 0x8651, .card = CX23885_BOARD_MYGICA_X8506, + }, { + .subvendor = 0x14f1, + .subdevice = 0x8657, + .card = CX23885_BOARD_MAGICPRO_PROHDTVE2, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -715,8 +723,9 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx23885_gpio_set(dev, GPIO_9); break; case CX23885_BOARD_MYGICA_X8506: + case CX23885_BOARD_MAGICPRO_PROHDTVE2: /* GPIO-1 reset XC5000 */ - /* GPIO-2 reset LGS8GL5 */ + /* GPIO-2 reset LGS8GL5 / LGS8G75 */ cx_set(GP0_IO, 0x00060000); cx_clear(GP0_IO, 0x00000006); mdelay(100); @@ -827,6 +836,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; case CX23885_BOARD_MYGICA_X8506: + case CX23885_BOARD_MAGICPRO_PROHDTVE2: ts1->gen_ctrl_val = 0x5; /* Parallel */ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index 86ac529e62b..e4a22dcaf59 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -487,6 +487,26 @@ static int cx23885_dvb_set_frontend(struct dvb_frontend *fe, port->set_frontend_save(fe, param) : -ENODEV; } +static struct lgs8gxx_config magicpro_prohdtve2_lgs8g75_config = { + .prod = LGS8GXX_PROD_LGS8G75, + .demod_address = 0x19, + .serial_ts = 0, + .ts_clk_pol = 1, + .ts_clk_gated = 1, + .if_clk_freq = 30400, /* 30.4 MHz */ + .if_freq = 6500, /* 6.50 MHz */ + .if_neg_center = 1, + .ext_adc = 0, + .adc_signed = 1, + .adc_vpp = 2, /* 1.6 Vpp */ + .if_neg_edge = 1, +}; + +static struct xc5000_config magicpro_prohdtve2_xc5000_config = { + .i2c_address = 0x61, + .if_khz = 6500, +}; + static int dvb_register(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; @@ -833,6 +853,19 @@ static int dvb_register(struct cx23885_tsport *port) &mygica_x8506_xc5000_config); } break; + case CX23885_BOARD_MAGICPRO_PROHDTVE2: + i2c_bus = &dev->i2c_bus[0]; + i2c_bus2 = &dev->i2c_bus[1]; + fe0->dvb.frontend = dvb_attach(lgs8gxx_attach, + &magicpro_prohdtve2_lgs8g75_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) { + dvb_attach(xc5000_attach, + fe0->dvb.frontend, + &i2c_bus2->i2c_adap, + &magicpro_prohdtve2_xc5000_config); + } + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 76a51509d8f..d68574d867c 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -76,6 +76,7 @@ #define CX23885_BOARD_HAUPPAUGE_HVR1255 20 #define CX23885_BOARD_HAUPPAUGE_HVR1210 21 #define CX23885_BOARD_MYGICA_X8506 22 +#define CX23885_BOARD_MAGICPRO_PROHDTVE2 23 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 -- cgit v1.2.3-70-g09d2 From af5f88c8776b2b9163460ff94127f68a9a0e02da Mon Sep 17 00:00:00 2001 From: Johannes Goerner Date: Thu, 9 Jul 2009 03:28:46 -0300 Subject: V4L/DVB (12281): gspca - sunplus: Webcam 052b:1803 added. Signed-off-by: Johannes Goerner Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/gspca.txt | 1 + drivers/media/video/gspca/sunplus.c | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 7045ebf1d72..37247697dbe 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -140,6 +140,7 @@ spca500 04fc:7333 PalmPixDC85 sunplus 04fc:ffff Pure DigitalDakota spca501 0506:00df 3Com HomeConnect Lite sunplus 052b:1513 Megapix V4 +sunplus 052b:1803 MegaImage VI tv8532 0545:808b Veo Stingray tv8532 0545:8333 Veo Stingray sunplus 0546:3155 Polaroid PDC3070 diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c index 5127bbf9dd2..eabad47a3ca 100644 --- a/drivers/media/video/gspca/sunplus.c +++ b/drivers/media/video/gspca/sunplus.c @@ -52,6 +52,7 @@ struct sd { #define LogitechClickSmart420 2 #define LogitechClickSmart820 3 #define MegapixV4 4 +#define MegaImageVI 5 u8 *jpeg_hdr; }; @@ -844,7 +845,10 @@ static int sd_config(struct gspca_dev *gspca_dev, break; case BRIDGE_SPCA533: cam->cam_mode = custom_mode; - cam->nmodes = sizeof custom_mode / sizeof custom_mode[0]; + if (sd->subtype == MegaImageVI) /* 320x240 only */ + cam->nmodes = ARRAY_SIZE(custom_mode) - 1; + else + cam->nmodes = ARRAY_SIZE(custom_mode); break; case BRIDGE_SPCA504C: cam->cam_mode = vga_mode2; @@ -988,7 +992,8 @@ static int sd_start(struct gspca_dev *gspca_dev) /* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA536: */ if (sd->subtype == MegapixV4 || - sd->subtype == LogitechClickSmart820) { + sd->subtype == LogitechClickSmart820 || + sd->subtype == MegaImageVI) { reg_w(gspca_dev, 0xf0, 0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); reg_r(gspca_dev, 0xf0, 4, 0); @@ -1384,6 +1389,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)}, {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)}, {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)}, + {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)}, {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)}, {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)}, {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)}, -- cgit v1.2.3-70-g09d2 From 1369738023900302ef9677c90c4da873b5593ee7 Mon Sep 17 00:00:00 2001 From: Steven Toth Date: Mon, 20 Jul 2009 15:37:25 -0300 Subject: V4L/DVB (12306): cx23885: Add support for ATSC/QAM on Hauppauge HVR-1850 cx23885: Add support for ATSC/QAM on Hauppauge HVR-1850 Signed-off-by: Steven Toth Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx23885 | 1 + drivers/media/video/cx23885/cx23885-cards.c | 49 ++++++++++++++++++++++++++++- drivers/media/video/cx23885/cx23885-dvb.c | 11 +++++++ drivers/media/video/cx23885/cx23885.h | 1 + 4 files changed, 61 insertions(+), 1 deletion(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885 index 19feb514f93..525edb37c75 100644 --- a/Documentation/video4linux/CARDLIST.cx23885 +++ b/Documentation/video4linux/CARDLIST.cx23885 @@ -22,3 +22,4 @@ 21 -> Hauppauge WinTV-HVR1210 [0070:2291,0070:2295] 22 -> Mygica X8506 DMB-TH [14f1:8651] 23 -> Magic-Pro ProHDTV Extreme 2 [14f1:8657] + 24 -> Hauppauge WinTV-HVR1850 [0070:8541] diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c index 2bf8ed604d6..3143d85ef31 100644 --- a/drivers/media/video/cx23885/cx23885-cards.c +++ b/drivers/media/video/cx23885/cx23885-cards.c @@ -205,6 +205,11 @@ struct cx23885_board cx23885_boards[] = { .name = "Magic-Pro ProHDTV Extreme 2", .portb = CX23885_MPEG_DVB, }, + [CX23885_BOARD_HAUPPAUGE_HVR1850] = { + .name = "Hauppauge WinTV-HVR1850", + .portb = CX23885_MPEG_ENCODER, + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -332,6 +337,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x14f1, .subdevice = 0x8657, .card = CX23885_BOARD_MAGICPRO_PROHDTVE2, + }, { + .subvendor = 0x0070, + .subdevice = 0x8541, + .card = CX23885_BOARD_HAUPPAUGE_HVR1850, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -491,8 +500,13 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) /* WinTV-HVR1700 (PCIe, OEM, No IR, full height) * DVB-T and MPEG2 HW Encoder */ break; + case 85021: + /* WinTV-HVR1850 (PCIe, OEM, RCA in, IR, FM, + Dual channel ATSC and MPEG2 HW Encoder */ + break; default: - printk(KERN_WARNING "%s: warning: unknown hauppauge model #%d\n", + printk(KERN_WARNING "%s: warning: " + "unknown hauppauge model #%d\n", dev->name, tv.model); break; } @@ -742,6 +756,36 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx_set(GP0_IO, 0x00060006); mdelay(100); break; + case CX23885_BOARD_HAUPPAUGE_HVR1850: + /* GPIO-0 656_CLK */ + /* GPIO-1 656_D0 */ + /* GPIO-2 Wake# */ + /* GPIO-3-10 cx23417 data0-7 */ + /* GPIO-11-14 cx23417 addr0-3 */ + /* GPIO-15-18 cx23417 READY, CS, RD, WR */ + /* GPIO-19 IR_RX */ + /* GPIO-20 C_IR_TX */ + /* GPIO-21 I2S DAT */ + /* GPIO-22 I2S WCLK */ + /* GPIO-23 I2S BCLK */ + /* ALT GPIO: EXP GPIO LATCH */ + + /* CX23417 GPIO's */ + /* GPIO-14 S5H1411/CX24228 Reset */ + /* GPIO-13 EEPROM write protect */ + mc417_gpio_enable(dev, GPIO_14 | GPIO_13, 1); + + /* Put the demod into reset and protect the eeprom */ + mc417_gpio_clear(dev, GPIO_14 | GPIO_13); + mdelay(100); + + /* Bring the demod out of reset */ + mc417_gpio_set(dev, GPIO_14); + mdelay(100); + + /* CX24228 GPIO */ + /* Connected to IF / Mux */ + break; } } @@ -758,6 +802,7 @@ int cx23885_ir_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1275: case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1210: + case CX23885_BOARD_HAUPPAUGE_HVR1850: /* FIXME: Implement me */ break; case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: @@ -797,6 +842,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1275: case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1210: + case CX23885_BOARD_HAUPPAUGE_HVR1850: if (dev->i2c_bus[0].i2c_rc == 0) hauppauge_eeprom(dev, eeprom+0xc0); break; @@ -864,6 +910,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1275: case CX23885_BOARD_HAUPPAUGE_HVR1255: case CX23885_BOARD_HAUPPAUGE_HVR1210: + case CX23885_BOARD_HAUPPAUGE_HVR1850: default: ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c index e4a22dcaf59..f87a023a735 100644 --- a/drivers/media/video/cx23885/cx23885-dvb.c +++ b/drivers/media/video/cx23885/cx23885-dvb.c @@ -866,6 +866,17 @@ static int dvb_register(struct cx23885_tsport *port) &magicpro_prohdtve2_xc5000_config); } break; + case CX23885_BOARD_HAUPPAUGE_HVR1850: + i2c_bus = &dev->i2c_bus[0]; + fe0->dvb.frontend = dvb_attach(s5h1411_attach, + &hcw_s5h1411_config, + &i2c_bus->i2c_adap); + if (fe0->dvb.frontend != NULL) + dvb_attach(tda18271_attach, fe0->dvb.frontend, + 0x60, &dev->i2c_bus[0].i2c_adap, + &hauppauge_tda18271_config); + break; + default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h index 0958d6a7ffd..963e6b17a43 100644 --- a/drivers/media/video/cx23885/cx23885.h +++ b/drivers/media/video/cx23885/cx23885.h @@ -77,6 +77,7 @@ #define CX23885_BOARD_HAUPPAUGE_HVR1210 21 #define CX23885_BOARD_MYGICA_X8506 22 #define CX23885_BOARD_MAGICPRO_PROHDTVE2 23 +#define CX23885_BOARD_HAUPPAUGE_HVR1850 24 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 -- cgit v1.2.3-70-g09d2 From e3e1920b28d47cb18b477fc9884b889f9622fc97 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Wed, 22 Jul 2009 21:02:44 -0300 Subject: V4L/DVB (12334): tuner-simple: Add an entry for the Partsnic PTI-5NF05 NTSC tuner Signed-off-by: Andy Walls Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.tuner | 1 + drivers/media/common/tuners/tuner-types.c | 25 +++++++++++++++++++++++++ include/media/tuner.h | 1 + 3 files changed, 27 insertions(+) (limited to 'Documentation') diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner index be67844074d..ba9fa679e2d 100644 --- a/Documentation/video4linux/CARDLIST.tuner +++ b/Documentation/video4linux/CARDLIST.tuner @@ -78,3 +78,4 @@ tuner=77 - TCL tuner MF02GIP-5N-E tuner=78 - Philips FMD1216MEX MK3 Hybrid Tuner tuner=79 - Philips PAL/SECAM multi (FM1216 MK5) tuner=80 - Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough +tuner=81 - Partsnic (Daewoo) PTI-5NF05 diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c index 6a7f1a417c2..5c6ef1e23c9 100644 --- a/drivers/media/common/tuners/tuner-types.c +++ b/drivers/media/common/tuners/tuner-types.c @@ -1301,6 +1301,25 @@ static struct tuner_params tuner_fq1216lme_mk3_params[] = { }, }; +/* ----- TUNER_PARTSNIC_PTI_5NF05 - Partsnic (Daewoo) PTI-5NF05 NTSC ----- */ + +static struct tuner_range tuner_partsnic_pti_5nf05_ranges[] = { + /* The datasheet specified channel ranges and the bandswitch byte */ + /* The control byte value of 0x8e is just a guess */ + { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, /* Channels 2 - B */ + { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, /* Channels C - W+11 */ + { 16 * 999.99 , 0x8e, 0x08, }, /* Channels W+12 - 69 */ +}; + +static struct tuner_params tuner_partsnic_pti_5nf05_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_partsnic_pti_5nf05_ranges, + .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_ranges), + .cb_first_if_lower_freq = 1, /* not specified but safe to do */ + }, +}; + /* --------------------------------------------------------------------- */ struct tunertype tuners[] = { @@ -1753,6 +1772,12 @@ struct tunertype tuners[] = { .params = tuner_fq1216lme_mk3_params, .count = ARRAY_SIZE(tuner_fq1216lme_mk3_params), }, + + [TUNER_PARTSNIC_PTI_5NF05] = { + .name = "Partsnic (Daewoo) PTI-5NF05", + .params = tuner_partsnic_pti_5nf05_params, + .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params), + }, }; EXPORT_SYMBOL(tuners); diff --git a/include/media/tuner.h b/include/media/tuner.h index cbf97f45fbe..c146f2f530b 100644 --- a/include/media/tuner.h +++ b/include/media/tuner.h @@ -126,6 +126,7 @@ #define TUNER_PHILIPS_FMD1216MEX_MK3 78 #define TUNER_PHILIPS_FM1216MK5 79 #define TUNER_PHILIPS_FQ1216LME_MK3 80 /* Active loopthrough, no FM */ +#define TUNER_PARTSNIC_PTI_5NF05 81 /* tv card specific */ #define TDA9887_PRESENT (1<<0) -- cgit v1.2.3-70-g09d2 From 6baefab531b22288be3b4ddef5671ea6469b09f8 Mon Sep 17 00:00:00 2001 From: Denis Loginov Date: Tue, 28 Jul 2009 03:39:10 -0300 Subject: V4L/DVB (12356): gspca - sonixj: Webcam 0c45:6148 added Signed-off-by: Denis Loginov Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/gspca.txt | 1 + drivers/media/video/gspca/sonixj.c | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 37247697dbe..b4370247013 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -287,6 +287,7 @@ sonixj 0c45:613a Microdia Sonix PC Camera sonixj 0c45:613b Surfer SN-206 sonixj 0c45:613c Sonix Pccam168 sonixj 0c45:6143 Sonix Pccam168 +sonixj 0c45:6148 Digitus DA-70811/ZSMC USB PC Camera ZS211/Microdia sn9c20x 0c45:6240 PC Camera (SN9C201 + MT9M001) sn9c20x 0c45:6242 PC Camera (SN9C201 + MT9M111) sn9c20x 0c45:6248 PC Camera (SN9C201 + OV9655) diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 3f3e1705ce7..f0b762f770f 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -2339,7 +2339,8 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)}, #endif {USB_DEVICE(0x0c45, 0x6100), BSI(SN9C120, MI0360, 0x5d)}, /*sn9c128*/ -/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x6102), BSI(SN9C120, PO2030N, ??)}, */ +/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6802, 0x21)}, */ {USB_DEVICE(0x0c45, 0x610a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c128*/ {USB_DEVICE(0x0c45, 0x610b), BSI(SN9C120, OV7660, 0x21)}, /*sn9c128*/ {USB_DEVICE(0x0c45, 0x610c), BSI(SN9C120, HV7131R, 0x11)}, /*sn9c128*/ @@ -2355,6 +2356,7 @@ static const __devinitdata struct usb_device_id device_table[] = { #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)}, #endif +/* {USB_DEVICE(0x0c45, 0x6132), BSI(SN9C120, OV7670, 0x21)}, */ {USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)}, {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x21)}, #if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE @@ -2362,7 +2364,9 @@ static const __devinitdata struct usb_device_id device_table[] = { #endif {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)}, {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x21)}, - {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)}, +/* {USB_DEVICE(0x0c45, 0x6142), BSI(SN9C120, PO2030N, ??)}, *sn9c120b*/ + {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, SP80708, 0x18)}, /*sn9c120b*/ + {USB_DEVICE(0x0c45, 0x6148), BSI(SN9C120, OM6802, 0x21)}, /*sn9c120b*/ {} }; MODULE_DEVICE_TABLE(usb, device_table); -- cgit v1.2.3-70-g09d2 From 575f9af89952c7e7703e48666d95609daaf99630 Mon Sep 17 00:00:00 2001 From: Mhayk Whandson Date: Tue, 28 Jul 2009 11:53:20 -0300 Subject: V4L/DVB (12370): v4l doc: fix cqcam source code path Fixed the c-qcam source code path in the linux kernel tree. Signed-off-by: Mhayk Whandson Signed-off-by: Randy Dunlap Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CQcam.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/CQcam.txt b/Documentation/video4linux/CQcam.txt index 04986efb731..d230878e473 100644 --- a/Documentation/video4linux/CQcam.txt +++ b/Documentation/video4linux/CQcam.txt @@ -18,8 +18,8 @@ Table of Contents 1.0 Introduction - The file ../drivers/char/c-qcam.c is a device driver for the -Logitech (nee Connectix) parallel port interface color CCD camera. + The file ../../drivers/media/video/c-qcam.c is a device driver for +the Logitech (nee Connectix) parallel port interface color CCD camera. This is a fairly inexpensive device for capturing images. Logitech does not currently provide information for developers, but many people have engineered several solutions for non-Microsoft use of the Color -- cgit v1.2.3-70-g09d2 From 4d14c833c0d5f926721da1e0b07287ab8b64f0ba Mon Sep 17 00:00:00 2001 From: Vlastimil Labsky Date: Mon, 10 Aug 2009 22:15:54 -0300 Subject: V4L/DVB (12439): cx88: add support for WinFast DTV2000H rev. J I updated and simplyfied patch from Zbynek Hrabovsky for recent kernel. It enables autodetection of card, sound in analog TV , sound in FM radio and switching between antenna and cable RF input. Radio tuner still doesn't work, I don't even know how it works. Some guys wrote me that FM radio works with TV tuner used instead of radio part (symlink video0 -> radio0). Cc: Gerd Knorr Signed-off-by: Vlastimil Labsky Signed-off-by: Andrew Morton Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.cx88 | 1 + drivers/media/video/cx88/cx88-cards.c | 49 +++++++++++++++++++++++++++++++++ drivers/media/video/cx88/cx88-dvb.c | 1 + drivers/media/video/cx88/cx88-input.c | 1 + drivers/media/video/cx88/cx88.h | 1 + 5 files changed, 53 insertions(+) (limited to 'Documentation') diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88 index 0736518b2f8..3385f8b094a 100644 --- a/Documentation/video4linux/CARDLIST.cx88 +++ b/Documentation/video4linux/CARDLIST.cx88 @@ -80,3 +80,4 @@ 79 -> Terratec Cinergy HT PCI MKII [153b:1177] 80 -> Hauppauge WinTV-IR Only [0070:9290] 81 -> Leadtek WinFast DTV1800 Hybrid [107d:6654] + 82 -> WinFast DTV2000 H rev. J [107d:6f2b] diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 39465301ec9..43aa7e06e5b 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -1283,6 +1283,51 @@ static const struct cx88_board cx88_boards[] = { }, .mpeg = CX88_MPEG_DVB, }, + [CX88_BOARD_WINFAST_DTV2000H_J] = { + .name = "WinFast DTV2000 H rev. J", + .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00017300, + .gpio1 = 0x00008207, + .gpio2 = 0x00000000, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x00018300, + .gpio1 = 0x0000f207, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x00018301, + .gpio1 = 0x0000f207, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x00018301, + .gpio1 = 0x0000f207, + .gpio2 = 0x00017304, + .gpio3 = 0x02000000, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x00015702, + .gpio1 = 0x0000f207, + .gpio2 = 0x00015702, + .gpio3 = 0x02000000, + }, + .mpeg = CX88_MPEG_DVB, + }, [CX88_BOARD_GENIATECH_DVBS] = { .name = "Geniatech DVB-S", .tuner_type = TUNER_ABSENT, @@ -2281,6 +2326,10 @@ static const struct cx88_subid cx88_subids[] = { .subvendor = 0x107d, .subdevice = 0x665e, .card = CX88_BOARD_WINFAST_DTV2000H, + },{ + .subvendor = 0x107d, + .subdevice = 0x6f2b, + .card = CX88_BOARD_WINFAST_DTV2000H_J, },{ .subvendor = 0x18ac, .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */ diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index e237b507659..1203e8d2c31 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -696,6 +696,7 @@ static int dvb_register(struct cx8802_dev *dev) } break; case CX88_BOARD_WINFAST_DTV2000H: + case CX88_BOARD_WINFAST_DTV2000H_J: case CX88_BOARD_HAUPPAUGE_HVR1100: case CX88_BOARD_HAUPPAUGE_HVR1100LP: case CX88_BOARD_HAUPPAUGE_HVR1300: diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index d91f5c51206..0abc3210072 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -225,6 +225,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->sampling = 1; break; case CX88_BOARD_WINFAST_DTV2000H: + case CX88_BOARD_WINFAST_DTV2000H_J: case CX88_BOARD_WINFAST_DTV1800H: ir_codes = ir_codes_winfast; ir->gpio_addr = MO_GP0_IO; diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index 9d83762163f..d5cea41f420 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -237,6 +237,7 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII 79 #define CX88_BOARD_HAUPPAUGE_IRONLY 80 #define CX88_BOARD_WINFAST_DTV1800H 81 +#define CX88_BOARD_WINFAST_DTV2000H_J 82 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, -- cgit v1.2.3-70-g09d2 From 3040b043423c1726a14595d500f6409070b1e722 Mon Sep 17 00:00:00 2001 From: Theodore Kilgore Date: Mon, 3 Aug 2009 04:13:23 -0300 Subject: V4L/DVB (12459): gspca - jeilinj: New subdriver for Jeilin chip. Signed-off-by: Theodore Kilgore Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/gspca.txt | 1 + drivers/media/video/gspca/Kconfig | 9 + drivers/media/video/gspca/Makefile | 2 + drivers/media/video/gspca/jeilinj.c | 388 ++++++++++++++++++++++++++++++++++++ 4 files changed, 400 insertions(+) create mode 100644 drivers/media/video/gspca/jeilinj.c (limited to 'Documentation') diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index b4370247013..76203a2213a 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -239,6 +239,7 @@ pac7311 093a:2626 Labtec 2200 pac7311 093a:2629 Genious iSlim 300 pac7311 093a:262a Webcam 300k pac7311 093a:262c Philips SPC 230 NC +jeilinj 0979:0280 Sakar 57379 zc3xx 0ac8:0302 Z-star Vimicro zc0302 vc032x 0ac8:0321 Vimicro generic vc0321 vc032x 0ac8:0323 Vimicro Vc0323 diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig index f114dd1507c..e800c22a9a8 100644 --- a/drivers/media/video/gspca/Kconfig +++ b/drivers/media/video/gspca/Kconfig @@ -47,6 +47,15 @@ config USB_GSPCA_FINEPIX To compile this driver as a module, choose M here: the module will be called gspca_finepix. +config USB_GSPCA_JEILINJ + tristate "Jeilin JPEG USB V4L2 driver" + depends on VIDEO_V4L2 && USB_GSPCA + help + Say Y here if you want support for cameras based on this Jeilin chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_jeilinj. + config USB_GSPCA_MARS tristate "Mars USB Camera Driver" depends on VIDEO_V4L2 && USB_GSPCA diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index f6d3b86e9ad..035616b5e86 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_USB_GSPCA) += gspca_main.o obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o +obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o @@ -30,6 +31,7 @@ gspca_main-objs := gspca.o gspca_conex-objs := conex.o gspca_etoms-objs := etoms.o gspca_finepix-objs := finepix.o +gspca_jeilinj-objs := jeilinj.o gspca_mars-objs := mars.o gspca_mr97310a-objs := mr97310a.o gspca_ov519-objs := ov519.o diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c new file mode 100644 index 00000000000..dbfa3ed6e8e --- /dev/null +++ b/drivers/media/video/gspca/jeilinj.c @@ -0,0 +1,388 @@ +/* + * Jeilinj subdriver + * + * Supports some Jeilin dual-mode cameras which use bulk transport and + * download raw JPEG data. + * + * Copyright (C) 2009 Theodore Kilgore + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define MODULE_NAME "jeilinj" + +#include +#include "gspca.h" +#include "jpeg.h" + +MODULE_AUTHOR("Theodore Kilgore "); +MODULE_DESCRIPTION("GSPCA/JEILINJ USB Camera Driver"); +MODULE_LICENSE("GPL"); + +/* Default timeouts, in ms */ +#define JEILINJ_CMD_TIMEOUT 500 +#define JEILINJ_DATA_TIMEOUT 1000 + +/* Maximum transfer size to use. */ +#define JEILINJ_MAX_TRANSFER 0x200 + +#define FRAME_HEADER_LEN 0x10 + +/* Structure to hold all of our device specific stuff */ +struct sd { + struct gspca_dev gspca_dev; /* !! must be the first item */ + const struct v4l2_pix_format *cap_mode; + /* Driver stuff */ + struct work_struct work_struct; + struct workqueue_struct *work_thread; + u8 quality; /* image quality */ + u8 jpegqual; /* webcam quality */ + u8 *jpeg_hdr; +}; + + struct jlj_command { + unsigned char instruction[2]; + unsigned char ack_wanted; + }; + +/* AFAICT these cameras will only do 320x240. */ +static struct v4l2_pix_format jlj_mode[] = { + { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0} +}; + +/* + * cam uses endpoint 0x03 to send commands, 0x84 for read commands, + * and 0x82 for bulk transfer. + */ + +/* All commands are two bytes only */ +static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command) +{ + int retval; + + memcpy(gspca_dev->usb_buf, command, 2); + retval = usb_bulk_msg(gspca_dev->dev, + usb_sndbulkpipe(gspca_dev->dev, 3), + gspca_dev->usb_buf, 2, NULL, 500); + if (retval < 0) + PDEBUG(D_ERR, "command write [%02x] error %d", + gspca_dev->usb_buf[0], retval); + return retval; +} + +/* Responses are one byte only */ +static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) +{ + int retval; + + retval = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x84), + gspca_dev->usb_buf, 1, NULL, 500); + response = gspca_dev->usb_buf[0]; + if (retval < 0) + PDEBUG(D_ERR, "read command [%02x] error %d", + gspca_dev->usb_buf[0], retval); + return retval; +} + +static int jlj_start(struct gspca_dev *gspca_dev) +{ + int i; + int retval = -1; + u8 response = 0xff; + struct jlj_command start_commands[] = { + {{0x71, 0x81}, 0}, + {{0x70, 0x05}, 0}, + {{0x95, 0x70}, 1}, + {{0x71, 0x81}, 0}, + {{0x70, 0x04}, 0}, + {{0x95, 0x70}, 1}, + {{0x71, 0x00}, 0}, + {{0x70, 0x08}, 0}, + {{0x95, 0x70}, 1}, + {{0x94, 0x02}, 0}, + {{0xde, 0x24}, 0}, + {{0x94, 0x02}, 0}, + {{0xdd, 0xf0}, 0}, + {{0x94, 0x02}, 0}, + {{0xe3, 0x2c}, 0}, + {{0x94, 0x02}, 0}, + {{0xe4, 0x00}, 0}, + {{0x94, 0x02}, 0}, + {{0xe5, 0x00}, 0}, + {{0x94, 0x02}, 0}, + {{0xe6, 0x2c}, 0}, + {{0x94, 0x03}, 0}, + {{0xaa, 0x00}, 0}, + {{0x71, 0x1e}, 0}, + {{0x70, 0x06}, 0}, + {{0x71, 0x80}, 0}, + {{0x70, 0x07}, 0} + }; + for (i = 0; i < ARRAY_SIZE(start_commands); i++) { + retval = jlj_write2(gspca_dev, start_commands[i].instruction); + if (retval < 0) + return retval; + if (start_commands[i].ack_wanted) + retval = jlj_read1(gspca_dev, response); + if (retval < 0) + return retval; + } + PDEBUG(D_ERR, "jlj_start retval is %d", retval); + return retval; +} + +static int jlj_stop(struct gspca_dev *gspca_dev) +{ + int i; + int retval; + struct jlj_command stop_commands[] = { + {{0x71, 0x00}, 0}, + {{0x70, 0x09}, 0}, + {{0x71, 0x80}, 0}, + {{0x70, 0x05}, 0} + }; + for (i = 0; i < ARRAY_SIZE(stop_commands); i++) { + retval = jlj_write2(gspca_dev, stop_commands[i].instruction); + if (retval < 0) + return retval; + } + return retval; +} + +/* This function is called as a workqueue function and runs whenever the camera + * is streaming data. Because it is a workqueue function it is allowed to sleep + * so we can use synchronous USB calls. To avoid possible collisions with other + * threads attempting to use the camera's USB interface the gspca usb_lock is + * used when performing the one USB control operation inside the workqueue, + * which tells the camera to close the stream. In practice the only thing + * which needs to be protected against is the usb_set_interface call that + * gspca makes during stream_off. Otherwise the camera doesn't provide any + * controls that the user could try to change. + */ + +static void jlj_dostream(struct work_struct *work) +{ + struct sd *dev = container_of(work, struct sd, work_struct); + struct gspca_dev *gspca_dev = &dev->gspca_dev; + struct gspca_frame *frame; + int blocks_left; /* 0x200-sized blocks remaining in current frame. */ + int size_in_blocks; + int act_len; + int discarding = 0; /* true if we failed to get space for frame. */ + int packet_type; + int ret; + u8 *buffer; + + buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA); + if (!buffer) { + PDEBUG(D_ERR, "Couldn't allocate USB buffer"); + goto quit_stream; + } + while (gspca_dev->present && gspca_dev->streaming) { + if (!gspca_dev->present) + goto quit_stream; + /* Start a new frame, and add the JPEG header, first thing */ + frame = gspca_get_i_frame(gspca_dev); + if (frame && !discarding) + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + dev->jpeg_hdr, JPEG_HDR_SZ); + else + discarding = 1; + /* + * Now request data block 0. Line 0 reports the size + * to download, in blocks of size 0x200, and also tells the + * "actual" data size, in bytes, which seems best to ignore. + */ + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x82), + buffer, JEILINJ_MAX_TRANSFER, &act_len, + JEILINJ_DATA_TIMEOUT); + PDEBUG(D_STREAM, + "Got %d bytes out of %d for Block 0", + act_len, JEILINJ_MAX_TRANSFER); + if (ret < 0 || act_len < FRAME_HEADER_LEN) + goto quit_stream; + size_in_blocks = buffer[0x0a]; + blocks_left = buffer[0x0a] - 1; + PDEBUG(D_STREAM, "blocks_left = 0x%x", blocks_left); + packet_type = INTER_PACKET; + if (frame && !discarding) + /* Toss line 0 of data block 0, keep the rest. */ + gspca_frame_add(gspca_dev, packet_type, + frame, buffer + FRAME_HEADER_LEN, + JEILINJ_MAX_TRANSFER - FRAME_HEADER_LEN); + else + discarding = 1; + while (blocks_left > 0) { + if (!gspca_dev->present) + goto quit_stream; + ret = usb_bulk_msg(gspca_dev->dev, + usb_rcvbulkpipe(gspca_dev->dev, 0x82), + buffer, JEILINJ_MAX_TRANSFER, &act_len, + JEILINJ_DATA_TIMEOUT); + if (ret < 0 || act_len < JEILINJ_MAX_TRANSFER) + goto quit_stream; + PDEBUG(D_STREAM, + "%d blocks remaining for frame", blocks_left); + blocks_left -= 1; + if (blocks_left == 0) + packet_type = LAST_PACKET; + else + packet_type = INTER_PACKET; + if (frame && !discarding) + gspca_frame_add(gspca_dev, packet_type, + frame, buffer, + JEILINJ_MAX_TRANSFER); + else + discarding = 1; + } + } +quit_stream: + mutex_lock(&gspca_dev->usb_lock); + if (gspca_dev->present) + jlj_stop(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + kfree(buffer); +} + +/* This function is called at probe time just before sd_init */ +static int sd_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct cam *cam = &gspca_dev->cam; + struct sd *dev = (struct sd *) gspca_dev; + + dev->quality = 85; + dev->jpegqual = 85; + PDEBUG(D_PROBE, + "JEILINJ camera detected" + " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + cam->cam_mode = jlj_mode; + cam->nmodes = 1; + cam->bulk = 1; + /* We don't use the buffer gspca allocates so make it small. */ + cam->bulk_size = 32; + INIT_WORK(&dev->work_struct, jlj_dostream); + return 0; +} + +/* called on streamoff with alt==0 and on disconnect */ +/* the usb_lock is held at entry - restore on exit */ +static void sd_stop0(struct gspca_dev *gspca_dev) +{ + struct sd *dev = (struct sd *) gspca_dev; + + /* wait for the work queue to terminate */ + mutex_unlock(&gspca_dev->usb_lock); + /* This waits for jlj_dostream to finish */ + destroy_workqueue(dev->work_thread); + dev->work_thread = NULL; + mutex_lock(&gspca_dev->usb_lock); + kfree(dev->jpeg_hdr); +} + +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + return 0; +} + +/* Set up for getting frames. */ +static int sd_start(struct gspca_dev *gspca_dev) +{ + struct sd *dev = (struct sd *) gspca_dev; + int ret; + + /* create the JPEG header */ + dev->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL); + jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width, + 0x21); /* JPEG 422 */ + jpeg_set_qual(dev->jpeg_hdr, dev->quality); + PDEBUG(D_STREAM, "Start streaming at 320x240"); + ret = jlj_start(gspca_dev); + if (ret < 0) { + PDEBUG(D_ERR, "Start streaming command failed"); + return ret; + } + /* Start the workqueue function to do the streaming */ + dev->work_thread = create_singlethread_workqueue(MODULE_NAME); + queue_work(dev->work_thread, &dev->work_struct); + + return 0; +} + +/* Table of supported USB devices */ +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x0979, 0x0280)}, + {} +}; + +MODULE_DEVICE_TABLE(usb, device_table); + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .config = sd_config, + .init = sd_init, + .start = sd_start, + .stop0 = sd_stop0, +}; + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return gspca_dev_probe(intf, id, + &sd_desc, + sizeof(struct sd), + THIS_MODULE); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + int ret; + + ret = usb_register(&sd_driver); + if (ret < 0) + return ret; + PDEBUG(D_PROBE, "registered"); + return 0; +} + +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); -- cgit v1.2.3-70-g09d2 From 3c1c48bbcf892e97c4e965b8528f4d735bf9a746 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 2 Jul 2009 11:50:35 -0300 Subject: V4L/DVB (12465): cx88: High resolution timer for Remote Controls Patch solves problem of missed keystrokes on some remote controls, as reported on http://bugzilla.kernel.org/show_bug.cgi?id=9637 . Signed-off-by: Andrzej Hajda Signed-off-by: Jean Delvare Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/cx88/cx88-input.c | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index c913e561419..dc0576afe5d 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -167,3 +167,4 @@ 166 -> Beholder BeholdTV 607 RDS [5ace:6073] 167 -> Beholder BeholdTV 609 RDS [5ace:6092] 168 -> Beholder BeholdTV 609 RDS [5ace:6093] +169 -> Compro VideoMate S350/S300 [185b:c900] diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 0abc3210072..79c4408a617 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -23,7 +23,7 @@ */ #include -#include +#include #include #include #include @@ -48,7 +48,7 @@ struct cx88_IR { /* poll external decoder */ int polling; - struct delayed_work work; + struct hrtimer timer; u32 gpio_addr; u32 last_gpio; u32 mask_keycode; @@ -144,19 +144,28 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) } } -static void cx88_ir_work(struct work_struct *work) +static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer) { - struct cx88_IR *ir = container_of(work, struct cx88_IR, work.work); + unsigned long missed; + struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer); cx88_ir_handle_key(ir); - schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); + missed = hrtimer_forward_now(&ir->timer, + ktime_set(0, ir->polling * 1000000)); + if (missed > 1) + ir_dprintk("Missed ticks %ld\n", missed - 1); + + return HRTIMER_RESTART; } void cx88_ir_start(struct cx88_core *core, struct cx88_IR *ir) { if (ir->polling) { - INIT_DELAYED_WORK(&ir->work, cx88_ir_work); - schedule_delayed_work(&ir->work, 0); + hrtimer_init(&ir->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + ir->timer.function = cx88_ir_work; + hrtimer_start(&ir->timer, + ktime_set(0, ir->polling * 1000000), + HRTIMER_MODE_REL); } if (ir->sampling) { core->pci_irqmask |= PCI_INT_IR_SMPINT; @@ -173,7 +182,7 @@ void cx88_ir_stop(struct cx88_core *core, struct cx88_IR *ir) } if (ir->polling) - cancel_delayed_work_sync(&ir->work); + hrtimer_cancel(&ir->timer); } /* ---------------------------------------------------------------------- */ -- cgit v1.2.3-70-g09d2 From 436e7e7c07ff153be6ee22220f47c7fa62176a26 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Sat, 8 Aug 2009 09:01:34 -0300 Subject: V4L/DVB (12554): FM TX: si4713: Add document file This patch adds a document file for si4713 device driver. It describes the driver interfaces and organization. Signed-off-by: Eduardo Valentin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/si4713.txt | 176 +++++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 Documentation/video4linux/si4713.txt (limited to 'Documentation') diff --git a/Documentation/video4linux/si4713.txt b/Documentation/video4linux/si4713.txt new file mode 100644 index 00000000000..25abdb78209 --- /dev/null +++ b/Documentation/video4linux/si4713.txt @@ -0,0 +1,176 @@ +Driver for I2C radios for the Silicon Labs Si4713 FM Radio Transmitters + +Copyright (c) 2009 Nokia Corporation +Contact: Eduardo Valentin + + +Information about the Device +============================ +This chip is a Silicon Labs product. It is a I2C device, currently on 0x63 address. +Basically, it has transmission and signal noise level measurement features. + +The Si4713 integrates transmit functions for FM broadcast stereo transmission. +The chip also allows integrated receive power scanning to identify low signal +power FM channels. + +The chip is programmed using commands and responses. There are also several +properties which can change the behavior of this chip. + +Users must comply with local regulations on radio frequency (RF) transmission. + +Device driver description +========================= +There are two modules to handle this device. One is a I2C device driver +and the other is a platform driver. + +The I2C device driver exports a v4l2-subdev interface to the kernel. +All properties can also be accessed by v4l2 extended controls interface, by +using the v4l2-subdev calls (g_ext_ctrls, s_ext_ctrls). + +The platform device driver exports a v4l2 radio device interface to user land. +So, it uses the I2C device driver as a sub device in order to send the user +commands to the actual device. Basically it is a wrapper to the I2C device driver. + +Applications can use v4l2 radio API to specify frequency of operation, mute state, +etc. But mostly of its properties will be present in the extended controls. + +When the v4l2 mute property is set to 1 (true), the driver will turn the chip off. + +Properties description +====================== + +The properties can be accessed using v4l2 extended controls. +Here is an output from v4l2-ctl util: +/ # v4l2-ctl -d /dev/radio0 --all -L +Driver Info: + Driver name : radio-si4713 + Card type : Silicon Labs Si4713 Modulator + Bus info : + Driver version: 0 + Capabilities : 0x00080800 + RDS Output + Modulator +Audio output: 0 (FM Modulator Audio Out) +Frequency: 1408000 (88.000000 MHz) +Video Standard = 0x00000000 +Modulator: + Name : FM Modulator + Capabilities : 62.5 Hz stereo rds + Frequency range : 76.0 MHz - 108.0 MHz + Subchannel modulation: stereo+rds + +User Controls + + mute (bool) : default=1 value=0 + +FM Radio Modulator Controls + + rds_signal_deviation (int) : min=0 max=90000 step=10 default=200 value=200 flags=slider + rds_program_id (int) : min=0 max=65535 step=1 default=0 value=0 + rds_program_type (int) : min=0 max=31 step=1 default=0 value=0 + rds_ps_name (str) : min=0 max=96 step=8 value='si4713 ' + rds_radio_text (str) : min=0 max=384 step=32 value='' + audio_limiter_feature_enabled (bool) : default=1 value=1 + audio_limiter_release_time (int) : min=250 max=102390 step=50 default=5010 value=5010 flags=slider + audio_limiter_deviation (int) : min=0 max=90000 step=10 default=66250 value=66250 flags=slider +audio_compression_feature_enabl (bool) : default=1 value=1 + audio_compression_gain (int) : min=0 max=20 step=1 default=15 value=15 flags=slider + audio_compression_threshold (int) : min=-40 max=0 step=1 default=-40 value=-40 flags=slider + audio_compression_attack_time (int) : min=0 max=5000 step=500 default=0 value=0 flags=slider + audio_compression_release_time (int) : min=100000 max=1000000 step=100000 default=1000000 value=1000000 flags=slider + pilot_tone_feature_enabled (bool) : default=1 value=1 + pilot_tone_deviation (int) : min=0 max=90000 step=10 default=6750 value=6750 flags=slider + pilot_tone_frequency (int) : min=0 max=19000 step=1 default=19000 value=19000 flags=slider + pre_emphasis_settings (menu) : min=0 max=2 default=1 value=1 + tune_power_level (int) : min=0 max=120 step=1 default=88 value=88 flags=slider + tune_antenna_capacitor (int) : min=0 max=191 step=1 default=0 value=110 flags=slider +/ # + +Here is a summary of them: + +* Pilot is an audible tone sent by the device. + +pilot_frequency - Configures the frequency of the stereo pilot tone. +pilot_deviation - Configures pilot tone frequency deviation level. +pilot_enabled - Enables or disables the pilot tone feature. + +* The si4713 device is capable of applying audio compression to the transmitted signal. + +acomp_enabled - Enables or disables the audio dynamic range control feature. +acomp_gain - Sets the gain for audio dynamic range control. +acomp_threshold - Sets the threshold level for audio dynamic range control. +acomp_attack_time - Sets the attack time for audio dynamic range control. +acomp_release_time - Sets the release time for audio dynamic range control. + +* Limiter setups audio deviation limiter feature. Once a over deviation occurs, +it is possible to adjust the front-end gain of the audio input and always +prevent over deviation. + +limiter_enabled - Enables or disables the limiter feature. +limiter_deviation - Configures audio frequency deviation level. +limiter_release_time - Sets the limiter release time. + +* Tuning power + +power_level - Sets the output power level for signal transmission. +antenna_capacitor - This selects the value of antenna tuning capacitor manually +or automatically if set to zero. + +* RDS related + +rds_ps_name - Sets the RDS ps name field for transmission. +rds_radio_text - Sets the RDS radio text for transmission. +rds_pi - Sets the RDS PI field for transmission. +rds_pty - Sets the RDS PTY field for transmission. + +* Region related + +preemphasis - sets the preemphasis to be applied for transmission. + +RNL +=== + +This device also has an interface to measure received noise level. To do that, you should +ioctl the device node. Here is an code of example: + +int main (int argc, char *argv[]) +{ + struct si4713_rnl rnl; + int fd = open("/dev/radio0", O_RDWR); + int rval; + + if (argc < 2) + return -EINVAL; + + if (fd < 0) + return fd; + + sscanf(argv[1], "%d", &rnl.frequency); + + rval = ioctl(fd, SI4713_IOC_MEASURE_RNL, &rnl); + if (rval < 0) + return rval; + + printf("received noise level: %d\n", rnl.rnl); + + close(fd); +} + +The struct si4713_rnl and SI4713_IOC_MEASURE_RNL are defined under +include/media/si4713.h. + +Stereo/Mono and RDS subchannels +=============================== + +The device can also be configured using the available sub channels for +transmission. To do that use S/G_MODULATOR ioctl and configure txsubchans properly. +Refer to v4l2-spec for proper use of this ioctl. + +Testing +======= +Testing is usually done with v4l2-ctl utility for managing FM tuner cards. +The tool can be found in v4l-dvb repository under v4l2-apps/util directory. + +Example for setting rds ps name: +# v4l2-ctl -d /dev/radio0 --set-ctrl=rds_ps_name="Dummy" + -- cgit v1.2.3-70-g09d2 From 5a5e1da579beb38fa8bf7d0a80cfa027cd7a2751 Mon Sep 17 00:00:00 2001 From: Vasiliy Temnikov Date: Wed, 26 Aug 2009 22:10:55 -0300 Subject: V4L/DVB (12574): support AverMedia Studio 505 Added support to AverMedia Studio 505 [dougsland@redhat.com: fixed rejects and removed the change to add dk as default secam variant] [mchehab@redhat.com: fix a few CodingStyle issues] Signed-off-by: Vasiliy Temnikov Signed-off-by: Andrew Morton Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/saa7134/saa7134-cards.c | 43 +++++++++++++++++++++++++++++ drivers/media/video/saa7134/saa7134-input.c | 1 + drivers/media/video/saa7134/saa7134.h | 1 + 4 files changed, 46 insertions(+) (limited to 'Documentation') diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index dc0576afe5d..31d9f14d6c3 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -168,3 +168,4 @@ 167 -> Beholder BeholdTV 609 RDS [5ace:6092] 168 -> Beholder BeholdTV 609 RDS [5ace:6093] 169 -> Compro VideoMate S350/S300 [185b:c900] +170 -> AverMedia AverTV Studio 505 [1461:a115] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 1a47e4a09b0..fbc55616faf 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -1364,6 +1364,42 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1, }, }, + [SAA7134_BOARD_AVERMEDIA_STUDIO_505] = { + /* Vasiliy Temnikov */ + .name = "AverMedia AverTV Studio 505", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .inputs = { { + .name = name_tv, + .vmux = 1, + .amux = LINE2, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + }, { + .name = name_comp2, + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + }, + .mute = { + .name = name_mute, + .amux = LINE1, + }, + }, [SAA7134_BOARD_UPMOST_PURPLE_TV] = { .name = "UPMOST PURPLE TV", .audio_clock = 0x00187de7, @@ -5398,6 +5434,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0x2115, .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_305, },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x1461, /* Avermedia Technologies Inc */ + .subdevice = 0xa115, + .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_505, + }, { .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7130, .subvendor = 0x1461, /* Avermedia Technologies Inc */ @@ -6508,6 +6550,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_KWORLD_VSTREAM_XPERT: case SAA7134_BOARD_KWORLD_XPERT: case SAA7134_BOARD_AVERMEDIA_STUDIO_305: + case SAA7134_BOARD_AVERMEDIA_STUDIO_505: case SAA7134_BOARD_AVERMEDIA_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_307: diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index bd0bfdea561..bfdecb953f9 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -445,6 +445,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_305: case SAA7134_BOARD_AVERMEDIA_307: case SAA7134_BOARD_AVERMEDIA_STUDIO_305: + case SAA7134_BOARD_AVERMEDIA_STUDIO_505: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_STUDIO_507: case SAA7134_BOARD_AVERMEDIA_STUDIO_507UA: diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index de9a7dd6508..7bba44688bf 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -293,6 +293,7 @@ struct saa7134_format { #define SAA7134_BOARD_BEHOLD_609RDS_MK3 167 #define SAA7134_BOARD_BEHOLD_609RDS_MK5 168 #define SAA7134_BOARD_VIDEOMATE_S350 169 +#define SAA7134_BOARD_AVERMEDIA_STUDIO_505 170 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3-70-g09d2 From 2012c87f8346ebf322826c3de5126d917ed75281 Mon Sep 17 00:00:00 2001 From: Dmitri Belimov Date: Wed, 26 Aug 2009 01:01:12 -0300 Subject: V4L/DVB (12587): Add support BeholdTV X7 card Add support our new TV card based on xc5000 and saa7134. Analog TV works well. Signed-off-by: Beholder Intl. Ltd. Dmitry Belimov Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/saa7134/saa7134-cards.c | 64 +++++++++++++++++++++++++++++ drivers/media/video/saa7134/saa7134-input.c | 1 + drivers/media/video/saa7134/saa7134.h | 1 + 4 files changed, 67 insertions(+) (limited to 'Documentation') diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index 31d9f14d6c3..cd0222d845d 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -169,3 +169,4 @@ 168 -> Beholder BeholdTV 609 RDS [5ace:6093] 169 -> Compro VideoMate S350/S300 [185b:c900] 170 -> AverMedia AverTV Studio 505 [1461:a115] +171 -> Beholder BeholdTV X7 [5ace:7595] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index fbc55616faf..a433a9b7f1e 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -32,6 +32,7 @@ #include #include "tea5767.h" #include "tda18271.h" +#include "xc5000.h" /* commly used strings */ static char name_mute[] = "mute"; @@ -5179,6 +5180,34 @@ struct saa7134_board saa7134_boards[] = { .amux = LINE1 } }, }, + [SAA7134_BOARD_BEHOLD_X7] = { + /* Beholder Intl. Ltd. Dmitry Belimov */ + .name = "Beholder BeholdTV X7", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_XC5000, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = { { + .name = name_tv, + .vmux = 2, + .amux = TV, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 0, + .amux = LINE1, + }, { + .name = name_svideo, + .vmux = 9, + .amux = LINE1, + } }, + .radio = { + .name = name_radio, + .amux = TV, + }, + }, + }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -6298,6 +6327,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x185b, .subdevice = 0xc900, .driver_data = SAA7134_BOARD_VIDEOMATE_S350, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x5ace, /* Beholder Intl. Ltd. */ + .subdevice = 0x7595, + .driver_data = SAA7134_BOARD_BEHOLD_X7, }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -6384,6 +6419,32 @@ static int saa7134_xc2028_callback(struct saa7134_dev *dev, return -EINVAL; } +static int saa7134_xc5000_callback(struct saa7134_dev *dev, + int command, int arg) +{ + switch (dev->board) { + case SAA7134_BOARD_BEHOLD_X7: + if (command == XC5000_TUNER_RESET) { + /* Down and UP pheripherial RESET pin for reset all chips */ + saa_writeb(SAA7134_SPECIAL_MODE, 0x00); + msleep(10); + saa_writeb(SAA7134_SPECIAL_MODE, 0x01); + msleep(10); + } + break; + default: + saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000); + saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000); + saa_andorl(SAA7133_ANALOG_IO_SELECT >> 2, 0x02, 0x02); + saa_andorl(SAA7134_ANALOG_IN_CTRL1 >> 2, 0x81, 0x81); + saa_andorl(SAA7134_AUDIO_CLOCK0 >> 2, 0x03187de7, 0x03187de7); + saa_andorl(SAA7134_AUDIO_PLL_CTRL >> 2, 0x03, 0x03); + saa_andorl(SAA7134_AUDIO_CLOCKS_PER_FIELD0 >> 2, + 0x0001e000, 0x0001e000); + break; + } + return 0; +} static int saa7134_tda8290_827x_callback(struct saa7134_dev *dev, int command, int arg) @@ -6480,6 +6541,8 @@ int saa7134_tuner_callback(void *priv, int component, int command, int arg) return saa7134_tda8290_callback(dev, command, arg); case TUNER_XC2028: return saa7134_xc2028_callback(dev, command, arg); + case TUNER_XC5000: + return saa7134_xc5000_callback(dev, command, arg); } } else { printk(KERN_ERR "saa7134: Error - device struct undefined.\n"); @@ -6728,6 +6791,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_BEHOLD_M63: case SAA7134_BOARD_BEHOLD_M6_EXTRA: case SAA7134_BOARD_BEHOLD_H6: + case SAA7134_BOARD_BEHOLD_X7: dev->has_remote = SAA7134_REMOTE_I2C; break; case SAA7134_BOARD_AVERMEDIA_A169_B: diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index bfdecb953f9..355fd247c4b 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -765,6 +765,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) case SAA7134_BOARD_BEHOLD_M63: case SAA7134_BOARD_BEHOLD_M6_EXTRA: case SAA7134_BOARD_BEHOLD_H6: + case SAA7134_BOARD_BEHOLD_X7: init_data.name = "BeholdTV"; init_data.get_key = get_key_beholdm6xx; init_data.ir_codes = ir_codes_behold; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 7bba44688bf..caefbf07d6f 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -294,6 +294,7 @@ struct saa7134_format { #define SAA7134_BOARD_BEHOLD_609RDS_MK5 168 #define SAA7134_BOARD_VIDEOMATE_S350 169 #define SAA7134_BOARD_AVERMEDIA_STUDIO_505 170 +#define SAA7134_BOARD_BEHOLD_X7 171 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3-70-g09d2 From 23389b8852e32824186c76fa4d87f818268adca1 Mon Sep 17 00:00:00 2001 From: Eugene Yudin Date: Sat, 29 Aug 2009 09:32:11 -0300 Subject: V4L/DVB (12589): Add support for RoverMedia TV Link Pro FM This patch add support for RoverMedia TV Link Pro FM (LR138 REV:I) card based on saa7134. Signed-off-by: Eugene Yudin Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.saa7134 | 1 + drivers/media/video/saa7134/saa7134-cards.c | 57 +++++++++++++++++++++++++++++ drivers/media/video/saa7134/saa7134-input.c | 1 + drivers/media/video/saa7134/saa7134.h | 1 + 4 files changed, 60 insertions(+) (limited to 'Documentation') diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134 index cd0222d845d..0ac4d254477 100644 --- a/Documentation/video4linux/CARDLIST.saa7134 +++ b/Documentation/video4linux/CARDLIST.saa7134 @@ -170,3 +170,4 @@ 169 -> Compro VideoMate S350/S300 [185b:c900] 170 -> AverMedia AverTV Studio 505 [1461:a115] 171 -> Beholder BeholdTV X7 [5ace:7595] +172 -> RoverMedia TV Link Pro FM [19d1:0138] diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index a433a9b7f1e..1b29487fd25 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -266,6 +266,56 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x10000, }, }, + [SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM] = { + /* RoverMedia TV Link Pro FM (LR138 REV:I) */ + /* Eugene Yudin */ + .name = "RoverMedia TV Link Pro FM", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MFPE05 2 */ + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0xe000, + .inputs = { { + .name = name_tv, + .vmux = 1, + .amux = TV, + .gpio = 0x8000, + .tv = 1, + }, { + .name = name_tv_mono, + .vmux = 1, + .amux = LINE2, + .gpio = 0x0000, + .tv = 1, + }, { + .name = name_comp1, + .vmux = 0, + .amux = LINE2, + .gpio = 0x4000, + }, { + .name = name_comp2, + .vmux = 3, + .amux = LINE2, + .gpio = 0x4000, + }, { + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + .gpio = 0x4000, + } }, + .radio = { + .name = name_radio, + .amux = LINE2, + .gpio = 0x2000, + }, + .mute = { + .name = name_mute, + .amux = TV, + .gpio = 0x8000, + }, + }, [SAA7134_BOARD_EMPRESS] = { /* "Gert Vervoort" */ .name = "EMPRESS", @@ -6333,6 +6383,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .subvendor = 0x5ace, /* Beholder Intl. Ltd. */ .subdevice = 0x7595, .driver_data = SAA7134_BOARD_BEHOLD_X7, + }, { + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x19d1, /* RoverMedia */ + .subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */ + .driver_data = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM, }, { /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, @@ -6663,6 +6719,7 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_REAL_ANGEL_220: case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG: case SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS: + case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM: dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_FLYDVBS_LR300: diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 355fd247c4b..65fb7b17b67 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -415,6 +415,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_FLYVIDEO3000: case SAA7134_BOARD_FLYTVPLATINUM_FM: case SAA7134_BOARD_FLYTVPLATINUM_MINI2: + case SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM: ir_codes = ir_codes_flyvideo; mask_keycode = 0xEC00000; mask_keydown = 0x0040000; diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index caefbf07d6f..ac74903a5bd 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -295,6 +295,7 @@ struct saa7134_format { #define SAA7134_BOARD_VIDEOMATE_S350 169 #define SAA7134_BOARD_AVERMEDIA_STUDIO_505 170 #define SAA7134_BOARD_BEHOLD_X7 171 +#define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172 #define SAA7134_MAXBOARDS 32 #define SAA7134_INPUT_MAX 8 -- cgit v1.2.3-70-g09d2 From 6d888a66be1c50c2f5193c53d6ea556e01dd60e3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 30 Aug 2009 13:05:56 -0300 Subject: V4L/DVB (12591): em28xx: Add entry for GADMEI UTV330+ and related IR keymap [mchehab@redhat.com: Fix a few wrong IR keymaps] Signed-off-by: Shine Liu Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.em28xx | 1 + drivers/media/common/ir-keymaps.c | 44 +++++++++++++++++++++++++++++++ drivers/media/video/em28xx/em28xx-cards.c | 22 ++++++++++++++++ drivers/media/video/em28xx/em28xx.h | 1 + include/media/ir-common.h | 1 + 5 files changed, 69 insertions(+) (limited to 'Documentation') diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index 66e5f829577..b37eff3c988 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -67,3 +67,4 @@ 69 -> KWorld ATSC 315U HDTV TV Box (em2882) [eb1a:a313] 70 -> Evga inDtube (em2882) 71 -> Silvercrest Webcam 1.3mpix (em2820/em2840) + 72 -> Gadmei UTV330+ (em2861) diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c index 0b8bfac1431..c93a5269f22 100644 --- a/drivers/media/common/ir-keymaps.c +++ b/drivers/media/common/ir-keymaps.c @@ -2826,3 +2826,47 @@ IR_KEYTAB_TYPE ir_codes_videomate_s350[IR_KEYTAB_SIZE] = { [0x20] = KEY_TEXT, }; EXPORT_SYMBOL_GPL(ir_codes_videomate_s350); + + +/* GADMEI UTV330+ RM008Z remote + Shine Liu + */ +IR_KEYTAB_TYPE ir_codes_gadmei_rm008z[IR_KEYTAB_SIZE] = { + [0x14] = KEY_POWER2, /* POWER OFF */ + [0x0c] = KEY_MUTE, /* MUTE */ + + [0x18] = KEY_TV, /* TV */ + [0x0e] = KEY_VIDEO, /* AV */ + [0x0b] = KEY_AUDIO, /* SV */ + [0x0f] = KEY_RADIO, /* FM */ + + [0x00] = KEY_1, + [0x01] = KEY_2, + [0x02] = KEY_3, + [0x03] = KEY_4, + [0x04] = KEY_5, + [0x05] = KEY_6, + [0x06] = KEY_7, + [0x07] = KEY_8, + [0x08] = KEY_9, + [0x09] = KEY_0, + [0x0a] = KEY_INFO, /* OSD */ + [0x1c] = KEY_BACKSPACE, /* LAST */ + + [0x0d] = KEY_PLAY, /* PLAY */ + [0x1e] = KEY_CAMERA, /* SNAPSHOT */ + [0x1a] = KEY_RECORD, /* RECORD */ + [0x17] = KEY_STOP, /* STOP */ + + [0x1f] = KEY_UP, /* UP */ + [0x44] = KEY_DOWN, /* DOWN */ + [0x46] = KEY_TAB, /* BACK */ + [0x4a] = KEY_ZOOM, /* FULLSECREEN */ + + [0x10] = KEY_VOLUMEUP, /* VOLUMEUP */ + [0x11] = KEY_VOLUMEDOWN, /* VOLUMEDOWN */ + [0x12] = KEY_CHANNELUP, /* CHANNELUP */ + [0x13] = KEY_CHANNELDOWN, /* CHANNELDOWN */ + [0x15] = KEY_ENTER, /* OK */ +}; +EXPORT_SYMBOL_GPL(ir_codes_gadmei_rm008z); diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 66c37768370..b184d482c49 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -558,6 +558,27 @@ struct em28xx_board em28xx_boards[] = { .amux = EM28XX_AMUX_LINE_IN, } }, }, + [EM2861_BOARD_GADMEI_UTV330PLUS] = { + .name = "Gadmei UTV330+", + .tuner_type = TUNER_TNF_5335MF, + .tda9887_conf = TDA9887_PRESENT, + .ir_codes = ir_codes_gadmei_rm008z, + .decoder = EM28XX_SAA711X, + .xclk = EM28XX_XCLK_FREQUENCY_12MHZ, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = EM28XX_AMUX_VIDEO, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, [EM2860_BOARD_TERRATEC_HYBRID_XS] = { .name = "Terratec Cinergy A Hybrid XS", .valid = EM28XX_BOARD_NOT_VALIDATED, @@ -1676,6 +1697,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = { {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, {0x1ba50080, EM2860_BOARD_SAA711X_REFERENCE_DESIGN, TUNER_ABSENT}, {0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC}, + {0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF}, }; /* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */ diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index a2add61f7d5..23f34dd691e 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -108,6 +108,7 @@ #define EM2882_BOARD_KWORLD_ATSC_315U 69 #define EM2882_BOARD_EVGA_INDTUBE 70 #define EM2820_BOARD_SILVERCREST_WEBCAM 71 +#define EM2861_BOARD_GADMEI_UTV330PLUS 72 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 diff --git a/include/media/ir-common.h b/include/media/ir-common.h index 8a607db492a..74a7e55734f 100644 --- a/include/media/ir-common.h +++ b/include/media/ir-common.h @@ -165,6 +165,7 @@ extern IR_KEYTAB_TYPE ir_codes_dm1105_nec[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_evga_indtube[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_terratec_cinergy_xs[IR_KEYTAB_SIZE]; extern IR_KEYTAB_TYPE ir_codes_videomate_s350[IR_KEYTAB_SIZE]; +extern IR_KEYTAB_TYPE ir_codes_gadmei_rm008z[IR_KEYTAB_SIZE]; #endif -- cgit v1.2.3-70-g09d2 From b5948bee1332eff719c074a760f99da9f02c7308 Mon Sep 17 00:00:00 2001 From: "Stephane Marguet (Stemp)" Date: Tue, 25 Aug 2009 04:14:04 -0300 Subject: V4L/DVB (12690): gspca - pac7311: Webcam 06f8:3009 added. Signed-off-by: Stephane Marguet (Stemp) Signed-off-by: Jean-Francois Moine Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/gspca.txt | 1 + drivers/media/video/gspca/pac7311.c | 1 + 2 files changed, 2 insertions(+) (limited to 'Documentation') diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 76203a2213a..4686e84dd80 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt @@ -183,6 +183,7 @@ ov534 06f8:3002 Hercules Blog Webcam ov534 06f8:3003 Hercules Dualpix HD Weblog sonixj 06f8:3004 Hercules Classic Silver sonixj 06f8:3008 Hercules Deluxe Optical Glass +pac7311 06f8:3009 Hercules Classic Link spca508 0733:0110 ViewQuest VQ110 spca508 0130:0130 Clone Digital Webcam 11043 spca501 0733:0401 Intel Create and Share diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index 0caf3c07573..052714484e8 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -1057,6 +1057,7 @@ static struct sd_desc sd_desc = { /* -- module initialisation -- */ static __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x06f8, 0x3009), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311}, -- cgit v1.2.3-70-g09d2 From ea47689e74a1637fac4f5fc44890f3662c976849 Mon Sep 17 00:00:00 2001 From: Douglas Schilling Landgraf Date: Sun, 6 Sep 2009 18:41:59 -0300 Subject: V4L/DVB (12720): em28xx-cards: Add vendor/product id for Kworld DVD Maker 2 Added Kworld DVD Maker 2 Thanks to C Western for reporting this board. Signed-off-by: Douglas Schilling Landgraf Signed-off-by: Mauro Carvalho Chehab --- Documentation/video4linux/CARDLIST.em28xx | 2 +- drivers/media/video/em28xx/em28xx-cards.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'Documentation') diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx index b37eff3c988..b13fcbd5d94 100644 --- a/Documentation/video4linux/CARDLIST.em28xx +++ b/Documentation/video4linux/CARDLIST.em28xx @@ -7,7 +7,7 @@ 6 -> Terratec Cinergy 200 USB (em2800) 7 -> Leadtek Winfast USB II (em2800) [0413:6023] 8 -> Kworld USB2800 (em2800) - 9 -> Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker (em2820/em2840) [1b80:e302,2304:0207,2304:021a] + 9 -> Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker (em2820/em2840) [1b80:e302,1b80:e304,2304:0207,2304:021a] 10 -> Hauppauge WinTV HVR 900 (em2880) [2040:6500] 11 -> Terratec Hybrid XS (em2880) [0ccd:0042] 12 -> Kworld PVR TV 2800 RF (em2820/em2840) diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index ec4763f73b2..7e3c78239fa 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -1037,7 +1037,8 @@ struct em28xx_board em28xx_boards[] = { } }, }, [EM2820_BOARD_PINNACLE_DVC_90] = { - .name = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker", + .name = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker " + "/ Kworld DVD Maker 2", .tuner_type = TUNER_ABSENT, /* capture only board */ .decoder = EM28XX_SAA711X, .input = { { @@ -1618,6 +1619,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2870_BOARD_KWORLD_355U }, { USB_DEVICE(0x1b80, 0xe302), .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kaiser Baas Video to DVD maker */ + { USB_DEVICE(0x1b80, 0xe304), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, /* Kworld DVD Maker 2 */ { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, { USB_DEVICE(0x0ccd, 0x004c), -- cgit v1.2.3-70-g09d2 From 2f82af08fcc7dc01a7e98a49a5995a77e32a2925 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 14 Sep 2009 03:25:28 -0400 Subject: Nicolas Pitre has a new email address Due to problems at cam.org, my nico@cam.org email address is no longer valid. FRom now on, nico@fluxnic.net should be used instead. Signed-off-by: Nicolas Pitre Signed-off-by: Linus Torvalds --- CREDITS | 2 +- Documentation/arm/SA1100/ADSBitsy | 2 +- Documentation/arm/SA1100/Assabet | 2 +- Documentation/arm/SA1100/Brutus | 2 +- Documentation/arm/SA1100/GraphicsClient | 4 ++-- Documentation/arm/SA1100/GraphicsMaster | 4 ++-- Documentation/arm/SA1100/Victor | 2 +- MAINTAINERS | 4 ++-- arch/arm/boot/compressed/head-sa1100.S | 2 +- arch/arm/lib/lib1funcs.S | 2 +- arch/arm/lib/sha1.S | 2 +- arch/arm/mach-sa1100/include/mach/assabet.h | 2 +- arch/arm/mach-sa1100/include/mach/hardware.h | 2 +- arch/arm/mach-sa1100/include/mach/memory.h | 2 +- arch/arm/mach-sa1100/include/mach/neponset.h | 2 +- arch/arm/mach-sa1100/include/mach/system.h | 2 +- arch/arm/mach-sa1100/include/mach/uncompress.h | 2 +- arch/arm/mach-sa1100/pm.c | 2 +- arch/arm/mach-sa1100/time.c | 2 +- arch/arm/mm/proc-xscale.S | 2 +- arch/arm/plat-iop/setup.c | 2 +- arch/arm/plat-omap/include/mach/system.h | 2 +- drivers/input/keyboard/pxa27x_keypad.c | 2 +- drivers/mtd/chips/cfi_cmdset_0001.c | 2 +- drivers/mtd/chips/cfi_cmdset_0020.c | 2 +- drivers/mtd/maps/bfin-async-flash.c | 2 +- drivers/mtd/maps/ceiva.c | 2 +- drivers/mtd/maps/dc21285.c | 4 ++-- drivers/mtd/maps/ipaq-flash.c | 2 +- drivers/mtd/maps/pxa2xx-flash.c | 2 +- drivers/mtd/maps/sa1100-flash.c | 2 +- drivers/mtd/mtdblock.c | 4 ++-- drivers/mtd/mtdpart.c | 2 +- drivers/net/smc91x.c | 4 ++-- drivers/net/smc91x.h | 2 +- drivers/rtc/rtc-sa1100.c | 2 +- drivers/video/sa1100fb.c | 2 +- include/linux/mtd/partitions.h | 2 +- lib/inflate.c | 2 +- 39 files changed, 45 insertions(+), 45 deletions(-) (limited to 'Documentation') diff --git a/CREDITS b/CREDITS index 1a41bf4addd..72b48786978 100644 --- a/CREDITS +++ b/CREDITS @@ -2800,7 +2800,7 @@ D: Starter of Linux1394 effort S: ask per mail for current address N: Nicolas Pitre -E: nico@cam.org +E: nico@fluxnic.net D: StrongARM SA1100 support integrator & hacker D: Xscale PXA architecture D: unified SMC 91C9x/91C11x ethernet driver (smc91x) diff --git a/Documentation/arm/SA1100/ADSBitsy b/Documentation/arm/SA1100/ADSBitsy index ab47c383390..7197a9e958e 100644 --- a/Documentation/arm/SA1100/ADSBitsy +++ b/Documentation/arm/SA1100/ADSBitsy @@ -40,4 +40,4 @@ Notes: mode, the timing is off so the image is corrupted. This will be fixed soon. -Any contribution can be sent to nico@cam.org and will be greatly welcome! +Any contribution can be sent to nico@fluxnic.net and will be greatly welcome! diff --git a/Documentation/arm/SA1100/Assabet b/Documentation/arm/SA1100/Assabet index 78bc1c1b04e..91f7ce7ba42 100644 --- a/Documentation/arm/SA1100/Assabet +++ b/Documentation/arm/SA1100/Assabet @@ -240,7 +240,7 @@ Then, rebooting the Assabet is just a matter of waiting for the login prompt. Nicolas Pitre -nico@cam.org +nico@fluxnic.net June 12, 2001 diff --git a/Documentation/arm/SA1100/Brutus b/Documentation/arm/SA1100/Brutus index 2254c8f0b32..b1cfd405dcc 100644 --- a/Documentation/arm/SA1100/Brutus +++ b/Documentation/arm/SA1100/Brutus @@ -60,7 +60,7 @@ little modifications. Any contribution is welcome. -Please send patches to nico@cam.org +Please send patches to nico@fluxnic.net Have Fun ! diff --git a/Documentation/arm/SA1100/GraphicsClient b/Documentation/arm/SA1100/GraphicsClient index 8fa7e8027ff..6c9c4f5a36e 100644 --- a/Documentation/arm/SA1100/GraphicsClient +++ b/Documentation/arm/SA1100/GraphicsClient @@ -4,7 +4,7 @@ For more details, contact Applied Data Systems or see http://www.applieddata.net/products.html The original Linux support for this product has been provided by -Nicolas Pitre . Continued development work by +Nicolas Pitre . Continued development work by Woojung Huh It's currently possible to mount a root filesystem via NFS providing a @@ -94,5 +94,5 @@ Notes: mode, the timing is off so the image is corrupted. This will be fixed soon. -Any contribution can be sent to nico@cam.org and will be greatly welcome! +Any contribution can be sent to nico@fluxnic.net and will be greatly welcome! diff --git a/Documentation/arm/SA1100/GraphicsMaster b/Documentation/arm/SA1100/GraphicsMaster index dd28745ac52..ee7c6595f23 100644 --- a/Documentation/arm/SA1100/GraphicsMaster +++ b/Documentation/arm/SA1100/GraphicsMaster @@ -4,7 +4,7 @@ For more details, contact Applied Data Systems or see http://www.applieddata.net/products.html The original Linux support for this product has been provided by -Nicolas Pitre . Continued development work by +Nicolas Pitre . Continued development work by Woojung Huh Use 'make graphicsmaster_config' before any 'make config'. @@ -50,4 +50,4 @@ Notes: mode, the timing is off so the image is corrupted. This will be fixed soon. -Any contribution can be sent to nico@cam.org and will be greatly welcome! +Any contribution can be sent to nico@fluxnic.net and will be greatly welcome! diff --git a/Documentation/arm/SA1100/Victor b/Documentation/arm/SA1100/Victor index 01e81fc4946..f938a29fdc2 100644 --- a/Documentation/arm/SA1100/Victor +++ b/Documentation/arm/SA1100/Victor @@ -9,7 +9,7 @@ Of course Victor is using Linux as its main operating system. The Victor implementation for Linux is maintained by Nicolas Pitre: nico@visuaide.com - nico@cam.org + nico@fluxnic.net For any comments, please feel free to contact me through the above addresses. diff --git a/MAINTAINERS b/MAINTAINERS index 837b5985ac4..64b9e447545 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3317,7 +3317,7 @@ S: Supported F: drivers/net/wireless/mwl8k.c MARVELL SOC MMC/SD/SDIO CONTROLLER DRIVER -M: Nicolas Pitre +M: Nicolas Pitre S: Maintained MARVELL YUKON / SYSKONNECT DRIVER @@ -4689,7 +4689,7 @@ F: include/linux/sl?b*.h F: mm/sl?b.c SMC91x ETHERNET DRIVER -M: Nicolas Pitre +M: Nicolas Pitre S: Maintained F: drivers/net/smc91x.* diff --git a/arch/arm/boot/compressed/head-sa1100.S b/arch/arm/boot/compressed/head-sa1100.S index 4c8c0e46027..6179d94dd5c 100644 --- a/arch/arm/boot/compressed/head-sa1100.S +++ b/arch/arm/boot/compressed/head-sa1100.S @@ -1,7 +1,7 @@ /* * linux/arch/arm/boot/compressed/head-sa1100.S * - * Copyright (C) 1999 Nicolas Pitre + * Copyright (C) 1999 Nicolas Pitre * * SA1100 specific tweaks. This is merged into head.S by the linker. * diff --git a/arch/arm/lib/lib1funcs.S b/arch/arm/lib/lib1funcs.S index 67964bcfc85..6dc06487f3c 100644 --- a/arch/arm/lib/lib1funcs.S +++ b/arch/arm/lib/lib1funcs.S @@ -1,7 +1,7 @@ /* * linux/arch/arm/lib/lib1funcs.S: Optimized ARM division routines * - * Author: Nicolas Pitre + * Author: Nicolas Pitre * - contributed to gcc-3.4 on Sep 30, 2003 * - adapted for the Linux kernel on Oct 2, 2003 */ diff --git a/arch/arm/lib/sha1.S b/arch/arm/lib/sha1.S index 09b548cac1a..eb0edb80d7b 100644 --- a/arch/arm/lib/sha1.S +++ b/arch/arm/lib/sha1.S @@ -3,7 +3,7 @@ * * SHA transform optimized for ARM * - * Copyright: (C) 2005 by Nicolas Pitre + * Copyright: (C) 2005 by Nicolas Pitre * Created: September 17, 2005 * * This program is free software; you can redistribute it and/or modify diff --git a/arch/arm/mach-sa1100/include/mach/assabet.h b/arch/arm/mach-sa1100/include/mach/assabet.h index 3959b20d5d1..28c2cf50c25 100644 --- a/arch/arm/mach-sa1100/include/mach/assabet.h +++ b/arch/arm/mach-sa1100/include/mach/assabet.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-sa1100/include/mach/assabet.h * - * Created 2000/06/05 by Nicolas Pitre + * Created 2000/06/05 by Nicolas Pitre * * This file contains the hardware specific definitions for Assabet * Only include this file from SA1100-specific files. diff --git a/arch/arm/mach-sa1100/include/mach/hardware.h b/arch/arm/mach-sa1100/include/mach/hardware.h index 60711822b12..99f5856d8de 100644 --- a/arch/arm/mach-sa1100/include/mach/hardware.h +++ b/arch/arm/mach-sa1100/include/mach/hardware.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-sa1100/include/mach/hardware.h * - * Copyright (C) 1998 Nicolas Pitre + * Copyright (C) 1998 Nicolas Pitre * * This file contains the hardware definitions for SA1100 architecture * diff --git a/arch/arm/mach-sa1100/include/mach/memory.h b/arch/arm/mach-sa1100/include/mach/memory.h index e9f8eed900f..d5277f9bee7 100644 --- a/arch/arm/mach-sa1100/include/mach/memory.h +++ b/arch/arm/mach-sa1100/include/mach/memory.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-sa1100/include/mach/memory.h * - * Copyright (C) 1999-2000 Nicolas Pitre + * Copyright (C) 1999-2000 Nicolas Pitre */ #ifndef __ASM_ARCH_MEMORY_H diff --git a/arch/arm/mach-sa1100/include/mach/neponset.h b/arch/arm/mach-sa1100/include/mach/neponset.h index d3f044f92c0..ffe2bc45eed 100644 --- a/arch/arm/mach-sa1100/include/mach/neponset.h +++ b/arch/arm/mach-sa1100/include/mach/neponset.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-sa1100/include/mach/neponset.h * - * Created 2000/06/05 by Nicolas Pitre + * Created 2000/06/05 by Nicolas Pitre * * This file contains the hardware specific definitions for Assabet * Only include this file from SA1100-specific files. diff --git a/arch/arm/mach-sa1100/include/mach/system.h b/arch/arm/mach-sa1100/include/mach/system.h index 942b153e251..ba9da9f7f18 100644 --- a/arch/arm/mach-sa1100/include/mach/system.h +++ b/arch/arm/mach-sa1100/include/mach/system.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-sa1100/include/mach/system.h * - * Copyright (c) 1999 Nicolas Pitre + * Copyright (c) 1999 Nicolas Pitre */ #include diff --git a/arch/arm/mach-sa1100/include/mach/uncompress.h b/arch/arm/mach-sa1100/include/mach/uncompress.h index 714160b03d7..6cb39ddde65 100644 --- a/arch/arm/mach-sa1100/include/mach/uncompress.h +++ b/arch/arm/mach-sa1100/include/mach/uncompress.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-sa1100/include/mach/uncompress.h * - * (C) 1999 Nicolas Pitre + * (C) 1999 Nicolas Pitre * * Reorganised to be machine independent. */ diff --git a/arch/arm/mach-sa1100/pm.c b/arch/arm/mach-sa1100/pm.c index 111cce67ad2..c83fdc80edf 100644 --- a/arch/arm/mach-sa1100/pm.c +++ b/arch/arm/mach-sa1100/pm.c @@ -15,7 +15,7 @@ * Save more value for the resume function! Support * Bitsy/Assabet/Freebird board * - * 2001-08-29: Nicolas Pitre + * 2001-08-29: Nicolas Pitre * Cleaned up, pushed platform dependent stuff * in the platform specific files. * diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c index 711c0295c66..95d92e8e56a 100644 --- a/arch/arm/mach-sa1100/time.c +++ b/arch/arm/mach-sa1100/time.c @@ -4,7 +4,7 @@ * Copyright (C) 1998 Deborah Wallach. * Twiddles (C) 1999 Hugo Fiennes * - * 2000/03/29 (C) Nicolas Pitre + * 2000/03/29 (C) Nicolas Pitre * Rewritten: big cleanup, much simpler, better HZ accuracy. * */ diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index 0cce37b9393..423394260bc 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S @@ -17,7 +17,7 @@ * * 2001 Sep 08: * Completely revisited, many important fixes - * Nicolas Pitre + * Nicolas Pitre */ #include diff --git a/arch/arm/plat-iop/setup.c b/arch/arm/plat-iop/setup.c index 9e573e78176..bade586fed0 100644 --- a/arch/arm/plat-iop/setup.c +++ b/arch/arm/plat-iop/setup.c @@ -1,7 +1,7 @@ /* * arch/arm/plat-iop/setup.c * - * Author: Nicolas Pitre + * Author: Nicolas Pitre * Copyright (C) 2001 MontaVista Software, Inc. * Copyright (C) 2004 Intel Corporation. * diff --git a/arch/arm/plat-omap/include/mach/system.h b/arch/arm/plat-omap/include/mach/system.h index 1060e345423..ed8ec747726 100644 --- a/arch/arm/plat-omap/include/mach/system.h +++ b/arch/arm/plat-omap/include/mach/system.h @@ -1,6 +1,6 @@ /* * Copied from arch/arm/mach-sa1100/include/mach/system.h - * Copyright (c) 1999 Nicolas Pitre + * Copyright (c) 1999 Nicolas Pitre */ #ifndef __ASM_ARCH_SYSTEM_H #define __ASM_ARCH_SYSTEM_H diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 76f9668221a..79cd3e9fdf2 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -8,7 +8,7 @@ * * Based on a previous implementations by Kevin O'Connor * and Alex Osborne and - * on some suggestions by Nicolas Pitre . + * on some suggestions by Nicolas Pitre . * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 8664feebc93..e7563a9872d 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -5,7 +5,7 @@ * (C) 2000 Red Hat. GPL'd * * - * 10/10/2000 Nicolas Pitre + * 10/10/2000 Nicolas Pitre * - completely revamped method functions so they are aware and * independent of the flash geometry (buswidth, interleave, etc.) * - scalability vs code size is completely set at compile-time diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 6c740f346f9..0667a671525 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * 10/10/2000 Nicolas Pitre + * 10/10/2000 Nicolas Pitre * - completely revamped method functions so they are aware and * independent of the flash geometry (buswidth, interleave, etc.) * - scalability vs code size is completely set at compile-time diff --git a/drivers/mtd/maps/bfin-async-flash.c b/drivers/mtd/maps/bfin-async-flash.c index 365c77b1b87..a7c808b577d 100644 --- a/drivers/mtd/maps/bfin-async-flash.c +++ b/drivers/mtd/maps/bfin-async-flash.c @@ -6,7 +6,7 @@ * for example. All board-specific configuration goes in your * board resources file. * - * Copyright 2000 Nicolas Pitre + * Copyright 2000 Nicolas Pitre * Copyright 2005-2008 Analog Devices Inc. * * Enter bugs at http://blackfin.uclinux.org/ diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c index 60e68bde0fe..d41f34766e5 100644 --- a/drivers/mtd/maps/ceiva.c +++ b/drivers/mtd/maps/ceiva.c @@ -9,7 +9,7 @@ * Based on: sa1100-flash.c, which has the following copyright: * Flash memory access on SA11x0 based devices * - * (C) 2000 Nicolas Pitre + * (C) 2000 Nicolas Pitre * */ diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c index 42969fe051b..b3cb3a18380 100644 --- a/drivers/mtd/maps/dc21285.c +++ b/drivers/mtd/maps/dc21285.c @@ -1,7 +1,7 @@ /* * MTD map driver for flash on the DC21285 (the StrongARM-110 companion chip) * - * (C) 2000 Nicolas Pitre + * (C) 2000 Nicolas Pitre * * This code is GPL */ @@ -249,5 +249,5 @@ module_exit(cleanup_dc21285); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Nicolas Pitre "); +MODULE_AUTHOR("Nicolas Pitre "); MODULE_DESCRIPTION("MTD map driver for DC21285 boards"); diff --git a/drivers/mtd/maps/ipaq-flash.c b/drivers/mtd/maps/ipaq-flash.c index 748c85f635f..76708e796b7 100644 --- a/drivers/mtd/maps/ipaq-flash.c +++ b/drivers/mtd/maps/ipaq-flash.c @@ -1,7 +1,7 @@ /* * Flash memory access on iPAQ Handhelds (either SA1100 or PXA250 based) * - * (C) 2000 Nicolas Pitre + * (C) 2000 Nicolas Pitre * (C) 2002 Hewlett-Packard Company * (C) 2003 Christian Pellegrin , : concatenation of multiple flashes */ diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index 643aa06b599..74fa075c838 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -175,5 +175,5 @@ module_init(init_pxa2xx_flash); module_exit(cleanup_pxa2xx_flash); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Nicolas Pitre "); +MODULE_AUTHOR("Nicolas Pitre "); MODULE_DESCRIPTION("MTD map driver for Intel XScale PXA2xx"); diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index c6210f5118d..fdb97f3d30e 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -1,7 +1,7 @@ /* * Flash memory access on SA11x0 based devices * - * (C) 2000 Nicolas Pitre + * (C) 2000 Nicolas Pitre */ #include #include diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 77db5ce24d9..2d70295a5fa 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -1,7 +1,7 @@ /* * Direct MTD block device access * - * (C) 2000-2003 Nicolas Pitre + * (C) 2000-2003 Nicolas Pitre * (C) 1999-2003 David Woodhouse */ @@ -403,5 +403,5 @@ module_exit(cleanup_mtdblock); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Nicolas Pitre et al."); +MODULE_AUTHOR("Nicolas Pitre et al."); MODULE_DESCRIPTION("Caching read/erase/writeback block device emulation access to MTD devices"); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 349fcbe5cc0..742504ea96f 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -1,7 +1,7 @@ /* * Simple MTD partitioning layer * - * (C) 2000 Nicolas Pitre + * (C) 2000 Nicolas Pitre * * This code is GPL * diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 61be6d7680f..05c91ee6921 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -35,7 +35,7 @@ * * contributors: * Daris A Nevil - * Nicolas Pitre + * Nicolas Pitre * Russell King * * History: @@ -58,7 +58,7 @@ * 22/09/04 Nicolas Pitre big update (see commit log for details) */ static const char version[] = - "smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre \n"; + "smc91x.c: v1.1, sep 22 2004 by Nicolas Pitre \n"; /* Debugging level */ #ifndef SMC_DEBUG diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 57a159fac99..784b631cfa3 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -28,7 +28,7 @@ . Authors . Erik Stahlman . Daris A Nevil - . Nicolas Pitre + . Nicolas Pitre . ---------------------------------------------------------------------------*/ #ifndef _SMC91X_H_ diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 4f247e4dd3f..021b2928f0b 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -9,7 +9,7 @@ * * Modifications from: * CIH - * Nicolas Pitre + * Nicolas Pitre * Andrew Christian * * Converted to the RTC subsystem and Driver Model diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c index 10ddad8e17d..cdaa873a605 100644 --- a/drivers/video/sa1100fb.c +++ b/drivers/video/sa1100fb.c @@ -66,7 +66,7 @@ * - FrameBuffer memory is now allocated at run-time when the * driver is initialized. * - * 2000/04/10: Nicolas Pitre + * 2000/04/10: Nicolas Pitre * - Big cleanup for dynamic selection of machine type at run time. * * 2000/07/19: Jamey Hicks diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h index b70313d33ff..274b6196091 100644 --- a/include/linux/mtd/partitions.h +++ b/include/linux/mtd/partitions.h @@ -1,7 +1,7 @@ /* * MTD partitioning layer definitions * - * (C) 2000 Nicolas Pitre + * (C) 2000 Nicolas Pitre * * This code is GPL */ diff --git a/lib/inflate.c b/lib/inflate.c index 1a8e8a97812..d10255973a9 100644 --- a/lib/inflate.c +++ b/lib/inflate.c @@ -7,7 +7,7 @@ * Adapted for booting Linux by Hannu Savolainen 1993 * based on gzip-1.0.3 * - * Nicolas Pitre , 1999/04/14 : + * Nicolas Pitre , 1999/04/14 : * Little mods for all variable to reside either into rodata or bss segments * by marking constant variables with 'const' and initializing all the others * at run-time only. This allows for the kernel uncompressor to run -- cgit v1.2.3-70-g09d2